"""Verify Git ignore/tracking states using only new repositories with a dummy .env.""" from pathlib import Path from datetime import datetime, timezone import argparse import hashlib import json import os import platform import subprocess import tempfile DUMMY='API_KEY=DUMMY_NOT_A_SECRET\n' def verify(): env={k:v for k,v in os.environ.items() if not k.startswith('GIT_')} env.update(GIT_CONFIG_NOSYSTEM='1',GIT_CONFIG_GLOBAL='/dev/null',GIT_CONFIG_SYSTEM='/dev/null',GIT_TERMINAL_PROMPT='0') commands=[] git_version=subprocess.check_output(['git','--version'],env=env,text=True).strip() with tempfile.TemporaryDirectory(prefix='ai-techo-gitignore-') as temporary: base=Path(temporary);hooks=base/'empty-hooks';hooks.mkdir() def git(repo,*args,expected=0): command=['git','-c','core.hooksPath='+str(hooks),'-c','user.name=AI Techo fixture','-c','user.email=fixture@example.invalid','-c','commit.gpgsign=false','-c','init.defaultBranch=main',*args] r=subprocess.run(command,cwd=repo,env=env,capture_output=True,text=True) commands.append({'repo':repo.name,'args':list(args),'exitCode':r.returncode,'stdout':r.stdout.replace(temporary,''),'stderr':r.stderr.replace(temporary,'')}) assert r.returncode==expected,(repo.name,args,r.returncode,r.stderr) return r.stdout untracked=base/'untracked';untracked.mkdir();git(untracked,'init','-q') (untracked/'.env').write_text(DUMMY);(untracked/'.gitignore').write_text('.env\n') assert git(untracked,'ls-files','--','.env')=='' assert git(untracked,'check-ignore','-v','--','.env')=='.gitignore:1:.env\t.env\n' states=[{'state':'untracked-and-ignored','workingFileExists':True,'inIndex':False,'inEarlierCommit':False}] # Commit is not required for a file to enter the index. (untracked/'.gitignore').unlink();git(untracked,'add','--','.env') assert git(untracked,'ls-files','--','.env')=='.env\n' (untracked/'.gitignore').write_text('.env\n') assert git(untracked,'check-ignore','-v','--','.env',expected=1)=='' assert git(untracked,'check-ignore','-v','--no-index','--','.env')=='.gitignore:1:.env\t.env\n' git(untracked,'rm','--cached','--','.env') assert git(untracked,'ls-files','--','.env')=='' assert git(untracked,'diff','--cached','--name-status','--','.env')=='' assert (untracked/'.env').read_text()==DUMMY new_file={'trackedAfterAddBeforeCommit':True,'stagedDeletionAfterRemoval':False,'workingFilePreserved':True} # A matching negation is printed by verbose mode, but does not ignore the file. (untracked/'.gitignore').write_text('.env\n!.env\n') assert git(untracked,'check-ignore','-v','--','.env')=='.gitignore:2:!.env\t.env\n' git(untracked,'check-ignore','-q','--','.env',expected=1) tracked=base/'tracked';tracked.mkdir();git(tracked,'init','-q') (tracked/'.env').write_text(DUMMY);git(tracked,'add','--','.env');git(tracked,'commit','-q','-m','fixture: add dummy env') before=git(tracked,'rev-parse','HEAD').strip() (tracked/'.gitignore').write_text('.env\n') assert git(tracked,'ls-files','--','.env')=='.env\n' assert git(tracked,'check-ignore','-v','--','.env',expected=1)=='' assert git(tracked,'check-ignore','-v','--no-index','--','.env')=='.gitignore:1:.env\t.env\n' assert git(tracked,'show',before+':.env')==DUMMY states.append({'state':'committed-before-ignore-rule','workingFileExists':True,'inIndex':True,'inEarlierCommit':True}) git(tracked,'rm','--cached','--','.env') assert git(tracked,'ls-files','--','.env')=='' assert git(tracked,'check-ignore','-v','--','.env')=='.gitignore:1:.env\t.env\n' assert git(tracked,'diff','--cached','--name-status','--','.env','.gitignore')=='D\t.env\n' assert (tracked/'.env').read_text()==DUMMY assert git(tracked,'show',before+':.env')==DUMMY states.append({'state':'removed-from-index-before-commit','workingFileExists':True,'inIndex':False,'inEarlierCommit':True,'stagedDeletion':True}) git(tracked,'add','--','.gitignore');git(tracked,'commit','-q','-m','fixture: ignore dummy env') assert git(tracked,'ls-files','--','.env')=='' assert git(tracked,'ls-tree','--name-only','HEAD','--','.env')=='' assert git(tracked,'show',before+':.env')==DUMMY assert (tracked/'.env').read_text()==DUMMY assert git(tracked,'remote')=='' and git(untracked,'remote')=='' states.append({'state':'removal-committed','workingFileExists':True,'inIndex':False,'inCurrentCommit':False,'inEarlierCommit':True}) return {'status':'passed','checkedAt':datetime.now(timezone.utc).isoformat(),'dateJST':'2026-10-21','gitVersion':git_version,'python':platform.python_version(), 'scriptSha256':hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),'dummyValue':DUMMY.strip(),'onlyNewTemporaryRepositories':True, 'globalAndSystemGitConfigDisabled':True,'emptyHooksDirectory':True,'remotesConfigured':False,'networkCommandsUsed':False, 'states':states,'addedButNotCommitted':new_file,'negationPatternChecked':True,'commandCount':len(commands),'commands':commands} if __name__=='__main__': parser=argparse.ArgumentParser();parser.add_argument('--out',default='gitignore-verification.json');args=parser.parse_args() result=verify();Path(args.out).write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n') print(json.dumps({'status':result['status'],'gitVersion':result['gitVersion'],'states':len(result['states']),'commands':result['commandCount']},ensure_ascii=False))