security: preserve verified Forgejo scanner activation and reconcile recovery
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Reject generated-only commits / generated-commit-guard (push) Successful in 7s

This commit is contained in:
codex 2026-10-13 11:31:06 +02:00
parent 78081dabf2
commit eb93eeedfd
19 changed files with 1542 additions and 8 deletions

View file

@ -516,6 +516,53 @@
"verified_at": "2026-10-11T23:23:28.882335+00:00",
"verified_outcome": "Exact source ConfigMap, generation 11 ready; health 200 and unauthenticated 403. Attended positive preview remains open.",
"refinement_or_rescue": false
},
{
"proposal_id": "FORGE6-NATIVE-PROBE-001",
"disposition": "unscored",
"outcome": "succeeded",
"original_revision": 1,
"original_digest_sha256": "b6fe6f55354f7f09837b94f4d75e79f39ac0a4b868f7ac377e2ca6590e340b42",
"proposal_ref": "docs/changes/CUST-WP-0080/receive-native-proposal.json",
"authorization_ref": "canon/standards/build-mode-change-authorization_v0.1.md",
"target": "railiance01 forgejo/forgejo-gitea-7d94988c79-8k76l new disposable /tmp probe only",
"expected_result": "Exact candidate binary on deployed image/Git accepts clean temporary pushes, rejects intermediate synthetic private key, discards quarantine, refuses unavailable scanner, recovers clean acceptance, retains dispatcher/additional-hook behavior; health remains passing and temporary area removed.",
"verification_ref": "docs/evidence/2026-10-12-netkingdom-security/receive-native-probe.json",
"rollback": "Remove only the new /tmp/custodian-receive-native-20261012-001 directory after matching .probe-owner. No existing repository/hook/config changes. Executor finally performs cleanup on success/failure.",
"abort_owner": "railiance-forge; executing custodian-codex",
"cost_estimate_eur": 0,
"risk_estimate": "Temporary approximately 27 MiB artifact storage plus small disposable Git fixtures and brief CPU use on the existing container; no new resource allocation/spend, no real credentials or production repository/config writes. Preflight requires 256 MiB free temporary space and passing health; execution has timeout and owned-path cleanup.",
"promotion_evidence": false,
"reason": "Existing standing founder authorization; not an exact-revision human approval, autopilot grant or credential-isolation proof.",
"executed_revision": 1,
"executed_digest_sha256": "b6fe6f55354f7f09837b94f4d75e79f39ac0a4b868f7ac377e2ca6590e340b42",
"verified_at": "2026-10-12T17:13:10.480151+00:00",
"verified_outcome": "Exact binaries passed disposable native push/detection/quarantine/failure/recovery/dispatcher checks in live image; existing service health passed, temporary directory removed. Production auth stubbed and hooks unchanged.",
"refinement_or_rescue": false
},
{
"proposal_id": "FORGE6-RECEIVE-ACTIVATION-001",
"authorization_ref": "canon/standards/build-mode-change-authorization_v0.1.md",
"expected_result": "22 existing upstream dispatchers gain independent pinned secret scanner; SSH clean/blocked results observed under independently tested temporary veto, rejected probe refs and quarantines absent, veto removed, existing hooks preserved and health passing. Subsequent authorized ordinary source push separately proves clean acceptance.",
"rollback": "Run the same executor with this proposal and --rollback. Removes only the two additive files after exact hash verification; verifies original eight-file inventory on all 22 repositories. Durable admitted binaries remain inert. Automatic rollback on failed activation verification.",
"abort_owner": "railiance-forge; executing custodian-codex",
"cost_estimate_eur": 0,
"risk_estimate": "Existing infrastructure, approximately 27 MiB durable storage and transient transfer copy, sequential small probes. Possible false refusals or bounded push latency on 22 repositories until rollback. No new spend/resources or credential scope; no restart. Temporary exact-ref veto prevents synthetic fixture publication. Scanner bounds: 90 seconds, 2000 objects, 8 MiB each, 64 MiB aggregate; larger pushes require reviewed remediation rather than bypass.",
"promotion_evidence": false,
"disposition": "unscored",
"outcome": "succeeded",
"original_revision": 1,
"original_digest_sha256": "9c8ea3b7fbe16a997359432af7bcf09f429881fd23cc567188c21129e80ccf8d",
"proposal_ref": "docs/changes/CUST-WP-0080/receive-hook-proposal.json",
"target": "railiance01 existing forgejo pod; additive pre-receive.d hooks on exactly 22 listed repositories",
"verification_ref": "docs/evidence/2026-10-12-netkingdom-security/receive-hook-activation.json",
"reason": "Existing standing founder blue-lane authorization; not an exact-revision human approval or autopilot grant.",
"prepared_at": "2026-10-12T17:28:10.890040+00:00",
"refinement_or_rescue": false,
"executed_revision": 1,
"executed_digest_sha256": "9c8ea3b7fbe16a997359432af7bcf09f429881fd23cc567188c21129e80ccf8d",
"verified_at": "2026-10-12T17:32:28.543884+00:00",
"verified_outcome": "Additive independent scanner installed on 22 exact repositories. Each actual SSH clean and synthetic-secret probe produced the expected scanner result under the temporary veto; probe refs and quarantined commits absent. Veto and staging removed, original hook inventory preserved, health passes. Normal clean acceptance remains separate."
}
]
}

View file

@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""Activate exact reviewed additive Forgejo hook profile and verify SSH refusals.
Synthetic pushes are always vetoed by a temporary independent hook. Existing
Forgejo hooks are hash-checked and preserved. No real credential is read and no
synthetic ref is retained. Native frontend/HTTP/new-repo coverage stays separate.
"""
import argparse
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import re
import shlex
import subprocess
import tempfile
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def helper(proposal):
path = Path(__file__).with_name('verify_receive_native.py')
if sha(__file__) != proposal['executor_sha256'] or sha(path) != proposal['native_helper_sha256']:
raise ValueError('executor-revision-changed')
spec = importlib.util.spec_from_file_location('native_receive_support', path)
module = importlib.util.module_from_spec(spec); spec.loader.exec_module(module)
return module
def shell(native, proposal, script, payload=None, timeout=60):
return native.execute(proposal, 'bash', '-c', 'set -euo pipefail\n' + script, payload=payload, timeout=timeout)
def repo_script(proposal, body):
names = proposal['repositories']
if len(names) != 22 or len(set(names)) != len(names) or any(not re.fullmatch(r'[a-z0-9-]+', n) for n in names):
raise ValueError('scope-refused')
return 'for name in ' + ' '.join(names) + '; do\nrepo=/data/git/gitea-repositories/coulomb/$name.git\n' + body + '\ndone\n'
def validate(proposal):
for name in [proposal['hook_name'], proposal['veto_name']]:
if not re.fullmatch(r'[a-z0-9-]+', name): raise ValueError('unsafe-hook-name')
if not re.fullmatch(r'/data/security/receive-secret-scan/[a-z0-9-]+', proposal['version_directory']):
raise ValueError('unsafe-version-directory')
if not re.fullmatch(r'refs/heads/custodian-g07-probe-[a-z0-9-]+', proposal['probe_ref']):
raise ValueError('unsafe-probe-ref')
def inspect(native, proposal, applied=False, sentinel=False):
validate(proposal)
prefix = proposal['hook_name']; veto = proposal['veto_name']
expected = dict(proposal['existing_hook_hashes'])
if applied: expected['pre-receive.d/' + prefix] = proposal['hook_sha256']
if sentinel: expected['pre-receive.d/' + veto] = proposal['veto_sha256']
body = '''test -d "$repo" && test ! -L "$repo" && test ! -L "$repo/hooks" && test ! -L "$repo/hooks/pre-receive.d"
test -z "$(find "$repo/hooks" -maxdepth 2 -type l -print -quit)"
printf 'REPO %s\n' "$name"
find "$repo/hooks" -maxdepth 2 -type f ! -name '*.sample' -exec sha256sum {} \\;
'''
if applied:
body += 'test -x "$repo/hooks/pre-receive.d/' + proposal['hook_name'] + '"\n'
if sentinel:
body += 'test -x "$repo/hooks/pre-receive.d/' + proposal['veto_name'] + '"\n'
raw = shell(native, proposal, repo_script(proposal, body)).decode()
rows = {}; current = None
for line in raw.splitlines():
if line.startswith('REPO '): current = line[5:]; rows[current] = {}
else:
digest, name = line.split(' ', 1)
if not re.fullmatch(r'[a-f0-9]{64}', digest): raise ValueError('invalid-hook-digest')
prefix_path = '/data/git/gitea-repositories/coulomb/' + current + '.git/hooks/'
if not name.startswith(prefix_path): raise ValueError('unexpected-hook-path')
rows[current][name[len(prefix_path):]] = digest
if set(rows) != set(proposal['repositories']) or any(v != expected for v in rows.values()):
raise ValueError('hook-inventory-changed')
return rows
def rollback(native, proposal):
validate(proposal)
for name, digest in [(proposal['hook_name'], proposal['hook_sha256']), (proposal['veto_name'], proposal['veto_sha256'])]:
body = 'path="$repo/hooks/pre-receive.d/' + name + '"\n'
body += 'if test -e "$path"; then test ! -L "$path"; test "$(sha256sum "$path" | cut -d" " -f1)" = ' + shlex.quote(digest) + '; fi\n'
shell(native, proposal, repo_script(proposal, body))
for name in [proposal['hook_name'], proposal['veto_name']]:
shell(native, proposal, repo_script(proposal, 'rm -f -- "$repo/hooks/pre-receive.d/' + name + '"'))
inspect(native, proposal)
def git(directory, args, payload=None, accepted=(0,)):
env = dict(os.environ)
for key in list(env):
if key.startswith('GIT_'): env.pop(key)
env.update(GIT_CONFIG_NOSYSTEM='1', GIT_CONFIG_GLOBAL='/dev/null', GIT_TERMINAL_PROMPT='0',
GIT_SSH_COMMAND='ssh -o BatchMode=yes -o ConnectTimeout=10')
r = subprocess.run(['/usr/bin/git', *args], cwd=directory, env=env, input=payload,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=120)
if r.returncode not in accepted:
raise ValueError('git-probe-command-failed')
return r
def verify_pushes(native, proposal):
fixture = Path(proposal['fixture_key'])
if sha(fixture) != proposal['fixture_sha256']: raise ValueError('fixture-changed')
rows = []
with tempfile.TemporaryDirectory(prefix='forge-receive-push-proof-') as temporary:
directory = Path(temporary)
git(directory, ['init', '-q', '-b', 'main'])
git(directory, ['config', 'core.hooksPath', '/dev/null'])
git(directory, ['config', 'user.name', 'Custodian disposable detector probe'])
git(directory, ['config', 'user.email', 'probe@example.test'])
(directory / 'source.txt').write_text('Disposable detector probe; intended to be rejected by a temporary veto.\n')
git(directory, ['add', 'source.txt']); git(directory, ['commit', '-qm', proposal['proposal_id'] + ' clean probe'])
clean = git(directory, ['rev-parse', 'HEAD']).stdout.decode().strip()
(directory / 'fixture.txt').write_bytes(fixture.read_bytes())
git(directory, ['add', 'fixture.txt']); git(directory, ['commit', '-qm', proposal['proposal_id'] + ' synthetic detector fixture'])
blocked = git(directory, ['rev-parse', 'HEAD']).stdout.decode().strip()
for number, name in enumerate(proposal['repositories']):
remote = 'forgejo-remote:coulomb/' + name + '.git'
if git(directory, ['ls-remote', remote, proposal['probe_ref']]).stdout.strip():
raise ValueError('probe-ref-already-exists')
row = {'repo': name}
for oid, status in [(clean, 'clean'), (blocked, 'blocked')]:
r = git(directory, ['push', '--porcelain', remote, oid + ':' + proposal['probe_ref']], accepted=(0, 1))
output = r.stdout + r.stderr
if r.returncode == 0:
# Only our newly created ref may be removed, with a lease.
git(directory, ['push', '--force-with-lease=' + proposal['probe_ref'] + ':' + oid,
remote, ':' + proposal['probe_ref']])
raise ValueError('independent-veto-failed-ref-removed')
if fixture.read_bytes().strip() in output: raise ValueError('synthetic-content-disclosed')
found = []
for line in output.splitlines():
match = re.search(rb'\{"status":.*\}', line)
if match:
try: found.append(json.loads(match.group()))
except ValueError: raise ValueError('malformed-control-receipt')
if len(found) != 1 or found[0].get('status') != status or b'CUSTODIAN_G07_PROBE_VETO' not in output:
raise ValueError('native-push-proof-incomplete')
row[status + '_scanner_result'] = status
if git(directory, ['ls-remote', remote, proposal['probe_ref']]).stdout.strip():
raise ValueError('unexpected-probe-ref-retained')
raw = native.execute(proposal, '/usr/bin/git', '--git-dir=/data/git/gitea-repositories/coulomb/' + name + '.git',
'cat-file', '--batch-check', payload=(blocked + '\n').encode()).decode().strip()
if raw != blocked + ' missing': raise ValueError('quarantine-object-retained')
row.update(temporary_veto_observed=True, probe_ref_absent=True, quarantined_commit_absent=True)
rows.append(row)
if (number + 1) % 5 == 0: print('Verified SSH refusal probes:', number + 1, 'of', len(proposal['repositories']), flush=True)
return rows
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('--proposal', type=Path, required=True); p.add_argument('--receipt', type=Path, required=True)
modes = p.add_mutually_exclusive_group()
modes.add_argument('--apply', action='store_true'); modes.add_argument('--rollback', action='store_true')
args = p.parse_args(); proposal = json.loads(args.proposal.read_text()); native = helper(proposal)
# Reuse only the read-only target/artifact preflight with its own pinned revision.
validate(proposal)
support = dict(proposal); support['executor_sha256'] = proposal['native_helper_sha256']
if args.rollback: support['artifacts'] = []
observation = native.preflight(support)
if args.rollback:
rollback(native, proposal); print('Prior hook inventory restored; admitted tools remain inert.'); return
inspect(native, proposal)
ref = shlex.quote(proposal['probe_ref'])
shell(native, proposal, repo_script(proposal, 'test -z "$(git --git-dir="$repo" for-each-ref --format=\'%(refname)\' ' + ref + ')"'))
if not args.apply:
print(json.dumps({'status': 'preflight-verified', 'repositories': len(proposal['repositories']), **observation})); return
temporary = '/tmp/' + proposal['directory_name']; version = proposal['version_directory']
receipt = {'proposal_id': proposal['proposal_id'], 'proposal_sha256': sha(args.proposal), 'result': 'unverified',
'observation': observation, 'phase': 'stage-tools', 'no_live_credentials_used': True,
'executed_revision': proposal['revision']}
created = changed = False
try:
native.execute(proposal, 'sh', '-c', 'umask 077; test ! -e "$1" && mkdir "$1" && printf "%s" "$2" > "$1/.probe-owner"',
'sh', temporary, proposal['proposal_id']); created = True
native.execute(proposal, 'tar', '-xmf', '-', '-C', temporary, payload=native.archive(proposal), timeout=90)
lines = ['cd ' + shlex.quote(temporary), 'sha256sum -c SHA256SUMS >/dev/null 2>&1']
for parent in ['/data/security', '/data/security/receive-secret-scan', version]:
lines.append('test ! -L ' + shlex.quote(parent))
lines.append('mkdir -p ' + shlex.quote(version))
for artifact in proposal['artifacts']:
if artifact['name'] not in ['receive-secret-scan', 'gitleaks']: continue
target = version + '/' + artifact['name']; quoted = shlex.quote(target)
lines.append('if test -e ' + quoted + '; then test ! -L ' + quoted + '; test "$(sha256sum ' + quoted + ' | cut -d" " -f1)" = ' + shlex.quote(artifact['sha256']) + '; else cp ' + shlex.quote(artifact['name']) + ' ' + quoted + '; fi')
lines.append('chmod 755 ' + quoted)
shell(native, proposal, '\n'.join(lines))
receipt['phase'] = 'install-hooks'; changed = True
body = ''
for field, source in [('veto_name', 'probe-veto'), ('hook_name', 'profile-hook')]:
dest = '"$repo/hooks/pre-receive.d/' + proposal[field] + '"'
body += 'test ! -e ' + dest + ' && test ! -L ' + dest + '\n'
body += 'staged=$(mktemp \"$repo/hooks/.custodian-install-XXXXXX\")\n'
body += 'cp ' + shlex.quote(temporary + '/' + source) + ' \"$staged\"\nchmod 755 \"$staged\"\nmv -n \"$staged\" ' + dest + '\n'
body += 'test ! -e \"$staged\"\n'
shell(native, proposal, repo_script(proposal, body))
inspect(native, proposal, applied=True, sentinel=True)
receipt['phase'] = 'verify-veto'
body = 'set +e\noutput=$(printf "%040d %040d %s\\n" 0 1 ' + ref + ' | "$repo/hooks/pre-receive.d/' + proposal['veto_name'] + '" 2>&1)\ncode=$?\nset -e\ntest "$code" = 1 && test "$output" = CUSTODIAN_G07_PROBE_VETO'
shell(native, proposal, repo_script(proposal, body))
receipt['phase'] = 'verify-ssh-pushes'
receipt['repositories'] = verify_pushes(native, proposal)
receipt['phase'] = 'remove-temporary-veto'
body = 'path="$repo/hooks/pre-receive.d/' + proposal['veto_name'] + '"\ntest "$(sha256sum "$path" | cut -d" " -f1)" = ' + shlex.quote(proposal['veto_sha256']) + '\nrm -- "$path"'
shell(native, proposal, repo_script(proposal, body))
inspect(native, proposal, applied=True)
native.execute(proposal, 'wget', '-qO', '/dev/null', 'http://127.0.0.1:3000/api/healthz')
receipt.update(result='verified', phase='active', temporary_veto_removed=True, health_after=True,
verification_limit='Synthetic pushes deliberately vetoed; scanner clean/detection results and quarantine absence verified. Normal clean acceptance needs the subsequent authorized source push; HTTP/frontend/lifecycle/outside-scope remain separate.')
except BaseException:
if changed:
try: rollback(native, proposal); receipt['rollback'] = 'prior hook inventory restored'
except BaseException: receipt['rollback'] = 'unverified; inspect exact target hashes'
raise
finally:
if created:
try:
native.execute(proposal, 'sh', '-c', 'test "$(cat "$1/.probe-owner")" = "$2" && rm -rf -- "$1" && test ! -e "$1"',
'sh', temporary, proposal['proposal_id'])
receipt['temporary_directory_removed'] = True
except BaseException:
receipt['temporary_directory_removed'] = False; receipt['result'] = 'unverified'
args.receipt.write_text(json.dumps(receipt, indent=2) + '\n')
if receipt['result'] != 'verified': raise ValueError('cleanup-incomplete')
print('Receive-path profile active for 22 repositories; SSH detector/veto/quarantine proofs verified.')
if __name__ == '__main__':
try: main()
except (ValueError, OSError, KeyError, subprocess.SubprocessError):
raise SystemExit('Activation refused or incomplete; inspect value-free receipt. Raw diagnostics suppressed.')

View file

@ -0,0 +1,34 @@
import json, subprocess, re, datetime
def command(args, payload=None):
r=subprocess.run(['kubectl','--request-timeout=15s',*args],input=payload,capture_output=True,text=True,timeout=35)
if r.returncode: raise SystemExit('Metadata observation failed; raw output suppressed.')
return r.stdout
def ready(p):
return p.get('status',{}).get('phase')=='Running' and any(c.get('type')=='Ready' and c.get('status')=='True' for c in p.get('status',{}).get('conditions',[]))
nodes=json.loads(command(['get','nodes','-o','json']))['items']
if len(nodes)!=1 or not any(a['address']=='92.205.62.239' for a in nodes[0]['status']['addresses']): raise SystemExit('Unexpected target host.')
pods=json.loads(command(['-n','forgejo','get','pods','-o','json']))['items']
apps=[p for p in pods if ready(p) and any(c['name']=='gitea' for c in p['spec']['containers'])]
if len(apps)!=1: raise SystemExit('Ambiguous forge pod.')
app=apps[0]
cluster=json.loads(command(['-n','databases','get','cluster','forgejo-db','-o','json']))
primary=cluster.get('status',{}).get('currentPrimary')
if not primary or not re.fullmatch(r'forgejo-db-[0-9]+',primary): raise SystemExit('No unambiguous database primary.')
query='BEGIN READ ONLY;\nSET LOCAL statement_timeout = \'5s\';\nSELECT json_build_object(\n \'repositories\',(SELECT json_agg(row_to_json(x) ORDER BY x.id) FROM\n (SELECT r.id,u.lower_name AS owner,r.lower_name AS name,r.is_private,r.is_empty,r.is_archived,r.is_mirror,r.is_fork,r.object_format_name,r.git_size,r.lfs_size,\n (SELECT count(*) FROM protected_branch b WHERE b.repo_id=r.id) AS protected_branch_rules,\n (SELECT json_agg(ru.type ORDER BY ru.type) FROM repo_unit ru WHERE ru.repo_id=r.id) AS unit_types\n FROM repository r JOIN "user" u ON u.id=r.owner_id) x)\n);\nROLLBACK;'
raw=command(['-n','databases','exec','-i',primary,'-c','postgres','--','psql','-X','-U','postgres','-d','forgejo','-Atq','-v','ON_ERROR_STOP=1'],query)
metadata=json.loads(raw)
versions=command(['-n','forgejo','exec',app['metadata']['name'],'-c','gitea','--','/usr/bin/git','--version']).strip()
directories=command(['-n','forgejo','exec',app['metadata']['name'],'-c','gitea','--','find','/data/git/gitea-repositories','-mindepth','2','-maxdepth','2','-type','d','-name','*.git']).splitlines()
relative=[]
for directory in directories:
path=directory.removeprefix('/data/git/gitea-repositories/')
if not re.fullmatch(r'[a-z0-9_.-]+/[a-z0-9_.-]+\.git',path): raise SystemExit('Unrecognized repository path; output suppressed.')
relative.append(path)
for repo in metadata['repositories']:
if not re.fullmatch(r'[a-z0-9_.-]+',repo['owner']) or not re.fullmatch(r'[a-z0-9_.-]+',repo['name']): raise SystemExit('Unrecognized repository identity; output suppressed.')
repo['main_directory_present']=repo['owner']+'/'+repo['name']+'.git' in relative
repo['wiki_directory_present']=repo['owner']+'/'+repo['name']+'.wiki.git' in relative
result={'observed_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'host':'railiance01','forge_pod':app['metadata']['name'],'forge_pod_uid':app['metadata']['uid'],'containers':[{'name':c['name'],'image':c['image'],'resources':c.get('resources',{})} for c in app['spec']['containers']],'database_primary':primary,'git_version':versions,'repositories':metadata['repositories'],'repository_directories':sorted(relative),'scope':'Read-only metadata: DB identifiers/flags/sizes/unit types/protected-rule counts and repository-directory presence. No descriptions, URLs, credentials, repository contents or logs read.'}
print(json.dumps(result,indent=2))

View file

@ -0,0 +1,63 @@
#!/bin/sh
# Disposable bare repositories only; caller owns admission and exact cleanup.
set +vx
set -eu
base=$1
cd "$base"
umask 077
export HOME="$base/home" GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null GIT_TERMINAL_PROMPT=0
mkdir home
trap 'chmod 755 "$base/gitleaks" >/dev/null 2>&1 || :' 0
sha256sum -c SHA256SUMS >/dev/null 2>&1
chmod 755 receive-secret-scan gitleaks
/usr/bin/git init -q --bare server.git
/usr/bin/git init -q -b main client
/usr/bin/git -C server.git config core.hooksPath "$base/server.git/hooks"
/usr/bin/git -C client config core.hooksPath "$base/no-client-hooks"
/usr/bin/git -C client config user.name 'Custodian disposable probe'
/usr/bin/git -C client config user.email 'probe@example.test'
mkdir server.git/hooks/pre-receive.d
cp pre-receive.fixture server.git/hooks/pre-receive
chmod 755 server.git/hooks/pre-receive
cat > server.git/hooks/pre-receive.d/gitea <<STUB
#!/bin/sh
cat >/dev/null
printf 'invoked\n' >> '$base/stub-calls'
STUB
cat > server.git/hooks/pre-receive.d/secret-scan <<HOOK
#!/bin/sh
exec '$base/receive-secret-scan' --scanner '$base/gitleaks'
HOOK
chmod 755 server.git/hooks/pre-receive.d/gitea server.git/hooks/pre-receive.d/secret-scan
printf 'clean baseline\n' > client/source.txt
/usr/bin/git -C client add source.txt
/usr/bin/git -C client commit -qm 'disposable clean baseline'
if ! /usr/bin/git -C client push "$base/server.git" HEAD:refs/heads/main > clean.out 2>&1; then exit 21; fi
grep -q '"status":"clean"' clean.out
initial=$(/usr/bin/git -C client rev-parse HEAD)
cp fixture-key client/secret.txt
/usr/bin/git -C client add secret.txt
/usr/bin/git -C client commit -qm 'disposable detector fixture'
rejected=$(/usr/bin/git -C client rev-parse HEAD)
/usr/bin/git -C client rm -q secret.txt
/usr/bin/git -C client commit -qm 'remove fixture from final tree'
if /usr/bin/git -C client push "$base/server.git" HEAD:refs/heads/main > blocked.out 2>&1; then exit 22; fi
grep -q '"status":"blocked"' blocked.out
if grep -q 'BEGIN OPENSSH PRIVATE KEY' blocked.out; then exit 23; fi
if /usr/bin/git -C server.git cat-file -e "$rejected" >/dev/null 2>&1; then exit 24; fi
test "$(/usr/bin/git -C server.git rev-parse refs/heads/main)" = "$initial"
/usr/bin/git -C client checkout -qb clean-retry "$initial"
printf 'clean recovery\n' > client/source.txt
/usr/bin/git -C client add source.txt
/usr/bin/git -C client commit -qm 'disposable clean recovery'
chmod 644 gitleaks
if /usr/bin/git -C client push "$base/server.git" HEAD:refs/heads/main > unavailable.out 2>&1; then exit 25; fi
grep -q '"status":"unverified"' unavailable.out
grep -q '"reason":"scanner-file-refused"' unavailable.out
chmod 755 gitleaks
if ! /usr/bin/git -C client push "$base/server.git" HEAD:refs/heads/main > recovered.out 2>&1; then exit 26; fi
grep -q '"status":"clean"' recovered.out
test "$(/usr/bin/git -C server.git rev-parse refs/heads/main)" = "$(/usr/bin/git -C client rev-parse HEAD)"
test "$(wc -l < stub-calls | tr -d ' ')" = 4
cmp pre-receive.fixture server.git/hooks/pre-receive
printf '{"clean_push":true,"intermediate_secret_refused":true,"quarantine_discarded":true,"scanner_unavailable_refused":true,"clean_after_recovery":true,"dispatcher_preserved":true,"other_hook_invocations":4,"builtin_authorization_stubbed":true}\n'

View file

@ -0,0 +1,71 @@
# Initial forge receive-hook activation
Owner work: FORGE-WP-0006-T02, coordinated through RMGR-WP-0021-T03 and
CUST-WP-0080 G07. The exact proposed action is `receive-hook-proposal.json`;
its executor and artifact hashes are immutable for that trial. The standing
build-mode authorization supplies the reversible-change authority; this is not
an independent owner approval, autopilot promotion, or credential-isolation proof.
## Composition and scope
The proposal enumerates 22 existing repositories, their eight original hook-file
hashes, the exact running pod/image, and two admitted Linux executables. Only an
additional `pre-receive.d/10-custodian-secret-scan` is retained. Generated Forgejo
dispatchers and authorization hooks remain byte-for-byte unchanged. Tool storage
is `/data/security/receive-secret-scan/20261012-57a0642b6251`, on the existing
persistent data volume. No user-authored arbitrary hook facility is enabled.
Metadata reconciliation found 165 repositories; the other 143 are uncovered,
not exempt. Actions enabled and branch-protection metadata do not prove required
CI checks, credential scope, or frontend lifecycle enforcement.
## Execution and rollback
From the Custodian checkout, default invocation performs read-only preflight:
```sh
python3 docs/changes/CUST-WP-0080/activate_receive_hooks.py \
--proposal docs/changes/CUST-WP-0080/receive-hook-proposal.json \
--receipt docs/evidence/2026-10-12-netkingdom-security/receive-hook-activation.json
```
`--apply` performs the exact mutation and writes its receipt; do not reapply to
an already installed profile. On failure after hook writes, automatic rollback
removes only the known added hook files and verifies the original inventory.
`--rollback` performs that same removal explicitly and does not require temporary
build artifacts. It retains the admitted tools as inert files. Explicit rollback
still verifies the pinned live target and health; if the pod has changed or health
is failing, the abort owner must review the current target before recovery. Never
edit the original proposal to disguise a changed execution revision.
Unknown hook modifications cause rollback refusal rather than deletion. Inspect
the receipt and exact path hashes; preserve evidence and resolve the concurrent
change with the forge owner. Temporary staging cleanup requires a matching owner
marker. No existing repository data, config, ref, account, or credential is removed
by ordinary rollback.
## Verification boundaries
The isolated native probe tests clean acceptance, intermediate-history detection,
scanner unavailability, quarantine discard and recovery using the exact deployed
image and binaries. Its Forgejo authorization hook is stubbed and the receipt
explicitly says so.
Activation uses the actual SSH transport and existing authorization hooks. A
separate, directly tested temporary hook vetoes the exact synthetic probe ref on
all 22 targets. Both clean and disposable-secret probes must therefore fail the
push, while the scanner must separately report `clean` and `blocked`. Ref absence
and quarantined-commit absence are checked. The temporary veto is removed only
after all probes pass. No synthetic key is valid for authentication or retained in
Git. Native probe logs and fixture material are not published.
These forced rejections alone do not prove normal clean acceptance. The next
ordinary authorized source push supplies that evidence, scoped to its repository
and commit. HTTP pushes, frontend edits/merges/imports, restart/hook regeneration,
new-repository reconciliation, historical/LFS/log/artifact coverage, and governed
finding-to-response acceptance remain open in the owner plan.
The installer rehearsal uses local stand-ins for transport and scanner, proving
installation/rollback behavior only. It covers partial installation recovery,
missing build artifacts during rollback, executable mode checks, and preservation
of unknown changes. It is not a substitute for either native receipt.

View file

@ -0,0 +1,92 @@
{
"pod": "forgejo-gitea-7d94988c79-8k76l",
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image": "code.forgejo.org/forgejo/forgejo:11.0.3-rootless",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"existing_dispatcher": "/data/git/gitea-repositories/coulomb/the-custodian.git/hooks/pre-receive",
"dispatcher_sha256": "38f2197d49b27f315e3487664802e56bc888d4afaec9e30b3bcc6bd461554aef",
"proposal_id": "FORGE6-RECEIVE-ACTIVATION-001",
"revision": 1,
"directory_name": "custodian-receive-native-activation-20261012-001",
"executor_sha256": "9b01ee383e16463981112226e19156b0de59af2d03dd71b9403e144e280a9fb3",
"native_helper_sha256": "c9120122c6f6f0b7c41fe4fa975e5a2a340e776885d852b861b8c13b7664adcd",
"repositories": [
"access-engine",
"approval-engine",
"audit-core",
"gate-house",
"glas-harness",
"key-cape",
"kings-guard",
"maturity-engine",
"net-kingdom",
"ops-mason",
"ops-warden",
"policy-nexus",
"railiance-forge",
"railiance-platform",
"repo-manager",
"role-engine",
"secrets-engine",
"security-canon",
"tenant-engine",
"the-custodian",
"user-engine",
"zone-engine"
],
"existing_hook_hashes": {
"proc-receive.d/gitea": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"post-receive.d/gitea": "a3a87fd152133783f14859bfa738eb3fcc38d3090147ad8df81724ed62fa97a5",
"pre-receive": "38f2197d49b27f315e3487664802e56bc888d4afaec9e30b3bcc6bd461554aef",
"proc-receive": "ca4eb127414b2c85164b9366a3311218ed7b5a2f6cac93c2d654da97e1ba4748",
"update": "a53caf562b0cdd47b08d20c27c63059ba41cd410c3264a61cda1a531f1810ae6",
"update.d/gitea": "d32f9f382dc1511c93e9e2ce61a60c068ac83a933376368b474faad1399be79f",
"post-receive": "38f2197d49b27f315e3487664802e56bc888d4afaec9e30b3bcc6bd461554aef",
"pre-receive.d/gitea": "2572c08b2aa9ec9db475f03e6ed43bf64d18f64f9a2364c5341ad277e31149fc"
},
"hook_name": "10-custodian-secret-scan",
"veto_name": "99-custodian-g07-probe-veto",
"hook_sha256": "b1d7cf8cd13feafe44e45876b1de3fdd9c88339d8d45791fa2b9f72ca832932b",
"veto_sha256": "a1c4b14f405fe687f32a36158d70fef8d6602cd0df0dad17a58edf48e67bc47b",
"version_directory": "/data/security/receive-secret-scan/20261012-57a0642b6251",
"probe_ref": "refs/heads/custodian-g07-probe-20261012-001",
"fixture_key": "/tmp/netkingdom-forge-admission/local-probe/fixture-key",
"fixture_sha256": "7f3c3a80af30e41ab13a7ce124e58b3863186a3fd68e3a9f78a274cf4de2d108",
"artifacts": [
{
"name": "receive-secret-scan",
"source": "/tmp/netkingdom-forge-admission/local-probe/receive-secret-scan",
"sha256": "57a0642b625105440fe146fceb4d244fd2dd08a75beb316831675643e6cc27ec",
"mode": 493
},
{
"name": "gitleaks",
"source": "/tmp/netkingdom-forge-admission/local-probe/gitleaks",
"sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"mode": 493
},
{
"name": "profile-hook",
"source": "/home/worsch/the-custodian/docs/changes/CUST-WP-0080/receive-profile-hook",
"sha256": "b1d7cf8cd13feafe44e45876b1de3fdd9c88339d8d45791fa2b9f72ca832932b",
"mode": 493
},
{
"name": "probe-veto",
"source": "/home/worsch/the-custodian/docs/changes/CUST-WP-0080/receive-probe-veto",
"sha256": "a1c4b14f405fe687f32a36158d70fef8d6602cd0df0dad17a58edf48e67bc47b",
"mode": 493
}
],
"lane": "blue",
"authorization_ref": "canon/standards/build-mode-change-authorization_v0.1.md",
"diff_ref": "docs/changes/CUST-WP-0080/activate_receive_hooks.py; receive-profile-hook; receive-probe-veto; exact hashes in this proposal",
"rollback": "Run the same executor with this proposal and --rollback. Removes only the two additive files after exact hash verification; verifies original eight-file inventory on all 22 repositories. Durable admitted binaries remain inert. Automatic rollback on failed activation verification.",
"abort_owner": "railiance-forge; executing custodian-codex",
"receipt_path": "docs/evidence/2026-10-12-netkingdom-security/receive-hook-activation.json",
"expected_result": "22 existing upstream dispatchers gain independent pinned secret scanner; SSH clean/blocked results observed under independently tested temporary veto, rejected probe refs and quarantines absent, veto removed, existing hooks preserved and health passing. Subsequent authorized ordinary source push separately proves clean acceptance.",
"cost_estimate_eur": 0,
"risk_estimate": "Existing infrastructure, approximately 27 MiB durable storage and transient transfer copy, sequential small probes. Possible false refusals or bounded push latency on 22 repositories until rollback. No new spend/resources or credential scope; no restart. Temporary exact-ref veto prevents synthetic fixture publication. Scanner bounds: 90 seconds, 2000 objects, 8 MiB each, 64 MiB aggregate; larger pushes require reviewed remediation rather than bypass.",
"verification_limit": "Initial reviewed 22 of 165 repositories only; HTTP/frontend/new-repository/restart/reconciliation and response workflow remain open. No historic content scan, live credential, or synthetic public ref publication authorized.",
"promotion_evidence": false
}

View file

@ -0,0 +1,65 @@
{
"proposal_id": "FORGE6-NATIVE-PROBE-001",
"revision": 1,
"pod": "forgejo-gitea-7d94988c79-8k76l",
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image": "code.forgejo.org/forgejo/forgejo:11.0.3-rootless",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"directory_name": "custodian-receive-native-20261012-001",
"executor_sha256": "c9120122c6f6f0b7c41fe4fa975e5a2a340e776885d852b861b8c13b7664adcd",
"artifacts": [
{
"name": "receive-secret-scan",
"source": "/tmp/netkingdom-forge-admission/local-probe/receive-secret-scan",
"sha256": "57a0642b625105440fe146fceb4d244fd2dd08a75beb316831675643e6cc27ec",
"mode": 493
},
{
"name": "gitleaks",
"source": "/tmp/netkingdom-forge-admission/local-probe/gitleaks",
"sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"mode": 493
},
{
"name": "probe.sh",
"source": "/tmp/netkingdom-forge-admission/local-probe/probe.sh",
"sha256": "0fcd8a582c7545bbc417310fbef9fc6eeb3e592db176cbcff7e19a58ee97963c",
"mode": 384
},
{
"name": "fixture-key",
"source": "/tmp/netkingdom-forge-admission/local-probe/fixture-key",
"sha256": "7f3c3a80af30e41ab13a7ce124e58b3863186a3fd68e3a9f78a274cf4de2d108",
"mode": 384
},
{
"name": "pre-receive.fixture",
"source": "/tmp/netkingdom-forge-admission/local-probe/pre-receive.fixture",
"sha256": "38f2197d49b27f315e3487664802e56bc888d4afaec9e30b3bcc6bd461554aef",
"mode": 384
}
],
"existing_dispatcher": "/data/git/gitea-repositories/coulomb/the-custodian.git/hooks/pre-receive",
"dispatcher_sha256": "38f2197d49b27f315e3487664802e56bc888d4afaec9e30b3bcc6bd461554aef",
"lane": "blue",
"authorization_ref": "canon/standards/build-mode-change-authorization_v0.1.md",
"diff_ref": "docs/changes/CUST-WP-0080/verify_receive_native.py and probe_receive_native.sh; locally rehearsed with exact artifact hashes",
"rollback": "Remove only the new /tmp/custodian-receive-native-20261012-001 directory after matching .probe-owner. No existing repository/hook/config changes. Executor finally performs cleanup on success/failure.",
"abort_owner": "railiance-forge; executing custodian-codex",
"receipt_path": "docs/evidence/2026-10-12-netkingdom-security/receive-native-probe.json",
"expected_result": "Exact candidate binary on deployed image/Git accepts clean temporary pushes, rejects intermediate synthetic private key, discards quarantine, refuses unavailable scanner, recovers clean acceptance, retains dispatcher/additional-hook behavior; health remains passing and temporary area removed.",
"verification_limit": "Builtin Forgejo authorization is a stub in an isolated unregistered bare repository. Does not prove installed SSH/HTTP/frontend/new-repository production enforcement.",
"cost_estimate_eur": 0,
"risk_estimate": "Temporary approximately 27 MiB artifact storage plus small disposable Git fixtures and brief CPU use on the existing container; no new resource allocation/spend, no real credentials or production repository/config writes. Preflight requires 256 MiB free temporary space and passing health; execution has timeout and owned-path cleanup.",
"local_rehearsal": {
"clean_push": true,
"intermediate_secret_refused": true,
"quarantine_discarded": true,
"scanner_unavailable_refused": true,
"clean_after_recovery": true,
"dispatcher_preserved": true,
"other_hook_invocations": 4,
"builtin_authorization_stubbed": true
},
"promotion_evidence": false
}

View file

@ -0,0 +1,11 @@
#!/bin/sh
set +vx
set -eu
blocked=0
while read -r old new ref; do
if [ "$ref" = "refs/heads/custodian-g07-probe-20261012-001" ]; then blocked=1; fi
done
if [ "$blocked" = 1 ]; then
echo CUSTODIAN_G07_PROBE_VETO >&2
exit 1
fi

View file

@ -0,0 +1,4 @@
#!/bin/sh
set +vx
set -eu
exec /data/security/receive-secret-scan/20261012-57a0642b6251/receive-secret-scan --scanner /data/security/receive-secret-scan/20261012-57a0642b6251/gitleaks

View file

@ -0,0 +1,81 @@
import copy
import importlib.util
import io
import json
from pathlib import Path
import subprocess
import sys
import tarfile
import tempfile
import unittest
from unittest.mock import patch
SOURCE=Path(__file__).with_name('activate_receive_hooks.py').resolve()
spec=importlib.util.spec_from_file_location('activation',SOURCE)
a=importlib.util.module_from_spec(spec);spec.loader.exec_module(a)
BASE=json.loads(SOURCE.with_name('receive-hook-proposal.json').read_text())
class Native:
def __init__(self, root, proposal, fail=False): self.root=root;self.p=proposal;self.fail=fail
def preflight(self,p):
for x in p['artifacts']:
if not Path(x['source']).is_file(): raise ValueError('missing-artifact')
return {'rehearsal':True}
def archive(self,p):
out=io.BytesIO();checks=[]
with tarfile.open(fileobj=out,mode='w') as t:
for item in p['artifacts']:
content=Path(item['source']).read_bytes();i=tarfile.TarInfo(item['name']);i.size=len(content);i.mode=item['mode'];t.addfile(i,io.BytesIO(content));checks.append(item['sha256']+' '+item['name']+'\n')
content=''.join(checks).encode();i=tarfile.TarInfo('SHA256SUMS');i.size=len(content);t.addfile(i,io.BytesIO(content))
return out.getvalue()
def execute(self,p,*args,payload=None,timeout=45):
if args[0]=='wget': return b''
mapped=[x.replace('/data/',str(self.root/'data')+'/').replace('/tmp/'+p['directory_name'],str(self.root/'stage')) for x in args]
if self.fail and args[0]=='bash' and 'mktemp' in args[-1]:
self.fail=False
path=self.root/'data/git/gitea-repositories/coulomb'/ (p['repositories'][0]+'.git/hooks/pre-receive.d')
for field,source in [('hook_name','receive-profile-hook'),('veto_name','receive-probe-veto')]:
dest=path/p[field];dest.write_bytes(SOURCE.with_name(source).read_bytes());dest.chmod(0o755)
raise ValueError('injected-partial-install-failure')
r=subprocess.run(mapped,input=payload,capture_output=True,timeout=timeout)
if r.returncode: raise ValueError('local-command-refused')
return r.stdout.replace((str(self.root/'data')+'/').encode(),b'/data/')
class Tests(unittest.TestCase):
def setUp(self):
self.tmp=tempfile.TemporaryDirectory();self.root=Path(self.tmp.name);self.p=copy.deepcopy(BASE)
# Small inert tools are sufficient for installer/rollback protocol testing.
binary=self.root/'tool';binary.write_text('#!/bin/sh\nexit 0\n')
for item in self.p['artifacts'][:2]: item.update(source=str(binary),sha256=a.sha(binary))
self.p['existing_hook_hashes']={k:a.hashlib.sha256(b'#!/bin/sh\nexit 0\n').hexdigest() for k in self.p['existing_hook_hashes']}
for name in self.p['repositories']:
repo=self.root/'data/git/gitea-repositories/coulomb'/(name+'.git')
subprocess.run(['git','init','--bare','-q',str(repo)],check=True)
for rel in self.p['existing_hook_hashes']:
f=repo/'hooks'/rel;f.parent.mkdir(exist_ok=True);f.write_bytes(binary.read_bytes());f.chmod(0o755)
self.native=Native(self.root,self.p);self.proposal=self.root/'proposal.json';self.receipt=self.root/'receipt.json'
def tearDown(self):self.tmp.cleanup()
def runmain(self,*args):
self.proposal.write_text(json.dumps(self.p))
with patch.object(a,'helper',return_value=self.native),patch.object(a,'verify_pushes',return_value=[{'rehearsal_only':True}]),patch.object(sys,'argv',['activate','--proposal',str(self.proposal),'--receipt',str(self.receipt),*args]):a.main()
def test_activation_and_rollback_without_build_files(self):
self.runmain('--apply');a.inspect(self.native,self.p,applied=True)
self.assertEqual(json.loads(self.receipt.read_text())['result'],'verified')
for x in self.p['artifacts']:x['source']='/missing/build/artifact'
self.runmain('--rollback');a.inspect(self.native,self.p)
def test_partial_install_rolls_back_all_added_hooks(self):
self.native.fail=True
with self.assertRaises(ValueError):self.runmain('--apply')
a.inspect(self.native,self.p)
r=json.loads(self.receipt.read_text());self.assertEqual(r['rollback'],'prior hook inventory restored');self.assertTrue(r['temporary_directory_removed']);self.assertEqual(r['result'],'unverified')
def test_non_executable_hook_refused(self):
self.runmain('--apply')
f=self.root/'data/git/gitea-repositories/coulomb'/(self.p['repositories'][0]+'.git/hooks/pre-receive.d')/self.p['hook_name'];f.chmod(0o644)
with self.assertRaises(ValueError):a.inspect(self.native,self.p,applied=True)
def test_rollback_preserves_unknown_modification(self):
self.runmain('--apply')
f=self.root/'data/git/gitea-repositories/coulomb'/(self.p['repositories'][0]+'.git/hooks/pre-receive.d')/self.p['hook_name'];f.write_text('unknown change\n')
with self.assertRaises(ValueError):a.rollback(self.native,self.p)
self.assertEqual(f.read_text(),'unknown change\n')
if __name__=='__main__':unittest.main(verbosity=2)

View file

@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""Exact-binary disposable probe in the admitted live Forgejo container.
No production repository, Git hook, credential, account, config or policy writes.
Default is read-only preflight; --apply creates only the exact new /tmp directory
and removes it after the probe, guarded by its unique owner marker.
"""
import argparse
import hashlib
import io
import json
import re
import shlex
import subprocess
import tarfile
from pathlib import Path
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def command(args, payload=None, timeout=45):
result = subprocess.run(['ssh', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10',
'railiance01', shlex.join(['kubectl', '--request-timeout=15s', *args])],
input=payload, capture_output=True, timeout=timeout)
if result.returncode:
raise ValueError('native-command-refused')
return result.stdout
def execute(proposal, *args, payload=None, timeout=45):
return command(['-n', 'forgejo', 'exec', '-i', proposal['pod'], '-c', 'gitea', '--', *args],
payload, timeout)
def preflight(proposal):
if not re.fullmatch(r'custodian-receive-native-[a-z0-9-]+', proposal['directory_name']):
raise ValueError('unsafe-probe-directory')
if proposal['executor_sha256'] != sha(__file__):
raise ValueError('executor-revision-changed')
nodes = json.loads(command(['get', 'nodes', '-o', 'json']))['items']
if len(nodes) != 1 or not any(a['address'] == '92.205.62.239' for a in nodes[0]['status']['addresses']):
raise ValueError('target-host-changed')
pod = json.loads(command(['-n', 'forgejo', 'get', 'pod', proposal['pod'], '-o', 'json']))
if pod['metadata']['uid'] != proposal['pod_uid']:
raise ValueError('target-pod-changed')
if not any(c['type'] == 'Ready' and c['status'] == 'True' for c in pod['status']['conditions']):
raise ValueError('target-pod-unready')
image = next(c['image'] for c in pod['spec']['containers'] if c['name'] == 'gitea')
if image != proposal['image']:
raise ValueError('target-image-changed')
image_id = next(c['imageID'] for c in pod['status']['containerStatuses'] if c['name'] == 'gitea')
if image_id != proposal['image_id']:
raise ValueError('target-image-digest-changed')
for item in proposal['artifacts']:
path = Path(item['source'])
if path.is_symlink() or not path.is_file() or sha(path) != item['sha256']:
raise ValueError('artifact-changed')
if not re.fullmatch(r'[a-zA-Z0-9._-]+', item['name']):
raise ValueError('artifact-name-refused')
df = execute(proposal, 'df', '-Pk', '/tmp').decode().splitlines()[-1].split()
if int(df[3]) < 256 * 1024:
raise ValueError('temporary-space-insufficient')
execute(proposal, 'wget', '-qO', '/dev/null', 'http://127.0.0.1:3000/api/healthz')
dispatcher = execute(proposal, 'sha256sum', proposal['existing_dispatcher']).decode().split()[0]
if dispatcher != proposal['dispatcher_sha256']:
raise ValueError('existing-dispatcher-changed')
return {'pod_uid': pod['metadata']['uid'], 'image_id': image_id,
'git_version': execute(proposal, '/usr/bin/git', '--version').decode().strip(),
'free_tmp_kib': int(df[3]), 'health_before': True}
def archive(proposal):
data = io.BytesIO()
checksums = []
with tarfile.open(fileobj=data, mode='w') as output:
for item in proposal['artifacts']:
content = Path(item['source']).read_bytes()
info = tarfile.TarInfo(item['name']); info.size = len(content); info.mode = item['mode']
info.uid = info.gid = 1000
output.addfile(info, io.BytesIO(content))
checksums.append(item['sha256'] + ' ' + item['name'] + '\n')
content = ''.join(checksums).encode()
info = tarfile.TarInfo('SHA256SUMS'); info.size = len(content); info.mode = 0o600
info.uid = info.gid = 1000
output.addfile(info, io.BytesIO(content))
return data.getvalue()
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--proposal', type=Path, required=True)
parser.add_argument('--receipt', type=Path, required=True)
parser.add_argument('--apply', action='store_true')
args = parser.parse_args()
proposal = json.loads(args.proposal.read_text())
observation = preflight(proposal)
if not args.apply:
print(json.dumps({'status': 'preflight-verified', **observation}))
return
directory = '/tmp/' + proposal['directory_name']
marker = proposal['proposal_id']
if not re.fullmatch(r'[A-Za-z0-9-]+', marker):
raise ValueError('unsafe-marker')
receipt = {'proposal_id': marker, 'proposal_sha256': sha(args.proposal),
'executed_revision': proposal['revision'], 'result': 'unverified', 'observation': observation,
'scope': 'exact binaries in disposable bare repositories inside existing Forgejo image; builtin auth stubbed',
'production_repositories_changed': False, 'live_credentials_used': False}
created = False
try:
execute(proposal, 'sh', '-c', 'umask 077; test ! -e "$1" && mkdir "$1" && printf "%s" "$2" > "$1/.probe-owner"',
'sh', directory, marker)
created = True
execute(proposal, 'tar', '-xmf', '-', '-C', directory, payload=archive(proposal), timeout=90)
raw = execute(proposal, 'timeout', '-k', '5', '150', 'sh', directory + '/probe.sh', directory, timeout=180)
result = json.loads(raw)
keys = ['clean_push', 'intermediate_secret_refused', 'quarantine_discarded',
'scanner_unavailable_refused', 'clean_after_recovery', 'dispatcher_preserved']
if not all(result.get(k) is True for k in keys) or result.get('other_hook_invocations') != 4:
raise ValueError('incomplete-native-proof')
receipt['verification'] = result
execute(proposal, 'wget', '-qO', '/dev/null', 'http://127.0.0.1:3000/api/healthz')
receipt['health_after'] = True
receipt['result'] = 'verified'
finally:
if created:
try:
execute(proposal, 'sh', '-c', 'test "$(cat "$1/.probe-owner")" = "$2" && rm -rf -- "$1" && test ! -e "$1"',
'sh', directory, marker)
receipt['temporary_directory_removed'] = True
except (ValueError, OSError, subprocess.SubprocessError):
receipt['temporary_directory_removed'] = False
receipt['result'] = 'unverified'
args.receipt.write_text(json.dumps(receipt, indent=2) + '\n')
if receipt['result'] != 'verified':
raise ValueError('verification-or-cleanup-incomplete')
print('Exact-binary native probe verified; temporary area removed; production hooks unchanged.')
if __name__ == '__main__':
try:
main()
except (ValueError, OSError, KeyError, StopIteration, subprocess.SubprocessError):
raise SystemExit('Native probe refused or incomplete; inspect value-free receipt. Raw diagnostics suppressed.')

View file

@ -0,0 +1,159 @@
{
"observed_at": "2026-10-12T17:14:48.732230+00:00",
"repositories": [
{
"repo": "access-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "approval-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "audit-core",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "gate-house",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "glas-harness",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "key-cape",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "kings-guard",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "maturity-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "net-kingdom",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "ops-mason",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "ops-warden",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "policy-nexus",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "railiance-forge",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "railiance-platform",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "repo-manager",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "role-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "secrets-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "security-canon",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "tenant-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "the-custodian",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "user-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
},
{
"repo": "zone-engine",
"shallow": false,
"object_format": "sha1",
"partial_config_keys": 0,
"head_gitlinks": 0
}
]
}

View file

@ -0,0 +1,188 @@
{
"observed_at": "2026-10-12T16:57:39.762249+00:00",
"host": "railiance01",
"pod": "forgejo-gitea-7d94988c79-8k76l",
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image": "code.forgejo.org/forgejo/forgejo:11.0.3-rootless",
"git_version": "git version 2.47.3",
"source_inventory_sha256": "e3ab33bd977544436532a804509cb94024abb5b0fa059a212992fb72f0eb9fac",
"counts": {
"database_repositories": 165,
"filesystem_directories": 165,
"public": 153,
"private": 12,
"archived": 0,
"mirrors": 0,
"forks": 0,
"empty": 0,
"wikis": 0,
"missing_main_directories": 0,
"repositories_with_protected_branch_rules": 0,
"actions_unit_enabled": 165
},
"reviewed_scope": [
{
"repository_id": 2,
"repo": "glas-harness",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 3,
"repo": "key-cape",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 9,
"repo": "railiance-platform",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 16,
"repo": "ops-warden",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 26,
"repo": "audit-core",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 42,
"repo": "access-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 60,
"repo": "railiance-forge",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 67,
"repo": "net-kingdom",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 71,
"repo": "secrets-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 76,
"repo": "the-custodian",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 77,
"repo": "user-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 92,
"repo": "tenant-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 93,
"repo": "kings-guard",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 102,
"repo": "ops-mason",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 108,
"repo": "repo-manager",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 113,
"repo": "role-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 124,
"repo": "policy-nexus",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 131,
"repo": "zone-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 137,
"repo": "gate-house",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 138,
"repo": "approval-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 139,
"repo": "maturity-engine",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
},
{
"repository_id": 157,
"repo": "security-canon",
"main_directory_present": true,
"protected_branch_rules": 0,
"actions_unit_enabled": true
}
],
"scope_disposition": {
"reviewed_initial_scope": 22,
"outside_initial_scope_not_exempt": 143,
"production_software_denominator_admitted": false,
"no_exemptions_inferred_from_archive_or_privacy_flags": true,
"production_gate_activated": false
},
"unit_type_source": "https://codeberg.org/forgejo/forgejo/src/tag/v11.0.3/models/unit/unit.go",
"limits": "Detailed unreviewed/private repository identities and size data remain in a local private observation; committed evidence contains aggregate counts and already-reviewed identities only. This metadata establishes no scanner enforcement or complete production denominator."
}

View file

@ -0,0 +1,21 @@
{
"scope": "installer rehearsal only; native transport and scanner replaced with local harness/inert binaries",
"tests_passed": 4,
"tests": [
"activation and rollback after build artifacts removed",
"partial installation failure restores original inventory",
"non-executable installed hook refused",
"unknown hook modification preserved during rollback"
],
"duration_seconds": 24.89,
"executor_sha256": "9b01ee383e16463981112226e19156b0de59af2d03dd71b9403e144e280a9fb3",
"test_source": "docs/changes/CUST-WP-0080/test_receive_activation.py",
"proposal_sha256": "9c8ea3b7fbe16a997359432af7bcf09f429881fd23cc567188c21129e80ccf8d",
"live_preflight": {
"result": "verified",
"repositories": 22,
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"existing_hooks_unchanged": true
}
}

View file

@ -0,0 +1,197 @@
{
"proposal_id": "FORGE6-RECEIVE-ACTIVATION-001",
"proposal_sha256": "9c8ea3b7fbe16a997359432af7bcf09f429881fd23cc567188c21129e80ccf8d",
"result": "verified",
"observation": {
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"git_version": "git version 2.47.3",
"free_tmp_kib": 115227300,
"health_before": true
},
"phase": "active",
"no_live_credentials_used": true,
"executed_revision": 1,
"repositories": [
{
"repo": "access-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "approval-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "audit-core",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "gate-house",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "glas-harness",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "key-cape",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "kings-guard",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "maturity-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "net-kingdom",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "ops-mason",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "ops-warden",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "policy-nexus",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "railiance-forge",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "railiance-platform",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "repo-manager",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "role-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "secrets-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "security-canon",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "tenant-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "the-custodian",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "user-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
},
{
"repo": "zone-engine",
"clean_scanner_result": "clean",
"blocked_scanner_result": "blocked",
"temporary_veto_observed": true,
"probe_ref_absent": true,
"quarantined_commit_absent": true
}
],
"temporary_veto_removed": true,
"health_after": true,
"verification_limit": "Synthetic pushes deliberately vetoed; scanner clean/detection results and quarantine absence verified. Normal clean acceptance needs the subsequent authorized source push; HTTP/frontend/lifecycle/outside-scope remain separate.",
"temporary_directory_removed": true
}

View file

@ -0,0 +1,28 @@
{
"proposal_id": "FORGE6-NATIVE-PROBE-001",
"proposal_sha256": "b6fe6f55354f7f09837b94f4d75e79f39ac0a4b868f7ac377e2ca6590e340b42",
"executed_revision": 1,
"result": "verified",
"observation": {
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"git_version": "git version 2.47.3",
"free_tmp_kib": 115282740,
"health_before": true
},
"scope": "exact binaries in disposable bare repositories inside existing Forgejo image; builtin auth stubbed",
"production_repositories_changed": false,
"live_credentials_used": false,
"verification": {
"clean_push": true,
"intermediate_secret_refused": true,
"quarantine_discarded": true,
"scanner_unavailable_refused": true,
"clean_after_recovery": true,
"dispatcher_preserved": true,
"other_hook_invocations": 4,
"builtin_authorization_stubbed": true
},
"health_after": true,
"temporary_directory_removed": true
}

View file

@ -0,0 +1,53 @@
{
"observed_at": "2026-10-13T08:47:08.601228+00:00",
"result": "verified",
"scope": "read-only deployed profile recheck; no push or mutation",
"proposal_id": "FORGE6-RECEIVE-ACTIVATION-001",
"proposal_sha256": "9c8ea3b7fbe16a997359432af7bcf09f429881fd23cc567188c21129e80ccf8d",
"observation": {
"pod_uid": "bc771b51-e9b8-456d-b59c-e7041704389d",
"image_id": "code.forgejo.org/forgejo/forgejo@sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba",
"git_version": "git version 2.47.3",
"free_tmp_kib": 114612720,
"health_before": true
},
"repositories": [
"access-engine",
"approval-engine",
"audit-core",
"gate-house",
"glas-harness",
"key-cape",
"kings-guard",
"maturity-engine",
"net-kingdom",
"ops-mason",
"ops-warden",
"policy-nexus",
"railiance-forge",
"railiance-platform",
"repo-manager",
"role-engine",
"secrets-engine",
"security-canon",
"tenant-engine",
"the-custodian",
"user-engine",
"zone-engine"
],
"original_hooks_preserved": true,
"installed_hooks_match": true,
"temporary_veto_absent": true,
"artifacts": [
{
"name": "receive-secret-scan",
"sha256": "57a0642b625105440fe146fceb4d244fd2dd08a75beb316831675643e6cc27ec",
"executable": true
},
{
"name": "gitleaks",
"sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"executable": true
}
]
}

View file

@ -1,6 +1,6 @@
# NetKingdom security gaps and closure sequence
Assessment date: 2026-10-12. [Blueprint](netkingdom-security-blueprint.md).
Assessment date: 2026-10-12; activation rechecked 2026-10-13. [Blueprint](netkingdom-security-blueprint.md).
Coordinator: CUST-WP-0080. Existing owner work remains authoritative. Statuses
below distinguish actual defects, incomplete integration and missing verification.
No whole-estate SEC-DSM conformance or maturity level is claimed.
@ -15,12 +15,12 @@ No whole-estate SEC-DSM conformance or maturity level is claimed.
| G04 | Credential inventory is incomplete and its five metadata fields do not by themselves establish full SEC-DSM lifecycle coverage. Mason's dated survey found 49 paths; coverage is not current estate-wide discovery. | MASON-WP-0004-T03/T04; RPF-WP-0035; CUST-WP-0080-T03 | Current metadata-only discovery denominator; owners/consumers/scopes; rotation and revocation procedures; unknown entries remain findings |
| G05 | Agent effective authority and credential isolation are unproven. Glas declares no ready profile; the Custodian record grants no autopilot authority. | CUST-WP-0073-T02/T04; GLAS-WP-0012 | Actual admitted agent identity, runtime read-denial and tool-effect restrictions, task expiry/cancel cleanup, no cross-task credential accumulation |
| G06 | Native evidence delivery, source completeness and attribution remain incomplete. Independent archive custody is not source completeness. | AUDIT-WP-0013/0014/0015; RPF-WP-0035-T08; existing FLEX-WP-0031 and NK-WP-0035/0040 residual records | Admitted sender, durable outbox, native archive readback, heartbeat/reconciliation and failure recovery. Residual work requires explicit promotion |
| G07 | The original generated-only hook accepted a disposable private-key commit. The pinned scanner is now enforced by actual configured hooks on 22 exact workstation checkouts; clean, synthetic-secret, generated-only and unavailable-scanner probes pass. Independent forge/CI prevention and response remain unverified. | RMGR-WP-0021-T01/T02 source and local activation done; T03 forge/CI via FORGE-WP-0006, T04 response open; CUST-WP-0080-T03 coordinates railiance-forge ownership | Deterministic production-repo inventory; actual prevention/detection runs; scanner findings kept private; finding-to-revocation procedure |
| G07 | The original generated-only hook accepted a disposable private-key commit. The pinned scanner is now enforced by actual configured hooks on 22 exact workstation checkouts; clean, synthetic-secret, generated-only and unavailable-scanner probes pass. The additive forge scanner is installed on the same 22 named repositories and SSH refusal probes passed; ordinary acceptance, other write paths, broader forge/CI coverage and response remain unverified. | RMGR-WP-0021-T01/T02 source and local activation done; T03 forge/CI via FORGE-WP-0006, T04 response open; CUST-WP-0080-T03 coordinates railiance-forge ownership | Deterministic production-repo inventory; actual prevention/detection runs; scanner findings kept private; finding-to-revocation procedure |
| G08 | Legacy root export and generation-prefix disclosure reproduced and removed in source. Bootstrap now uses a registered public recipient, explicit temporary-key resume and an encrypted handoff bound to the bundle digest. Other custody callers and native recovery acceptance remain unverified. | NK-WP-0049 T01 repaired; T02 caller reconciliation; T03 native recovery. NK-WP-0045 covers only the non-secret root-grant record; CUST-WP-0073 retains isolation/incident work | Inspect actual bootstrap callers; stop secret output reaching model/logs; owner-reviewed safe recovery procedure and tests |
| G09 | Rotation and revocation closure are incomplete: existing exposure rotation is founder-deferred, npm migration remains open, and five-field descriptions do not prove consumer adoption. | CUST-WP-0073-T05; SECRETS-WP-0006-T06; WARDEN-WP-0037-T03; RPF-WP-0035-T07 | For each relevant credential: new consumer accepted, old credential refused, copies reconciled; explicit DSM exception if still deferred |
| G10 | Build-mode exceptions and close-down checklist do not uniformly contain DSM-EXC requirement, risk, compensating controls and review fields. | CUST-WP-0080-T03; existing security-close-down checklist and October 11 decisions | Requirement-level exception records with real approval references and revalidation; no invented approval or retroactive conformance |
| G11 | Root recovery, independent custody and single-node resilience require scoped native proof. Old successful source preparation is insufficient. | WARDEN-WP-0027-T02; platform recovery records; RPF-WP-0015 residual | Fresh authorized scenario, off-host encrypted backup, independent recovery access, verified restore/return; honor build-mode single-holder decision |
| G12 | CI credential authority, Kubernetes delivery-copy lifecycle and at-rest protection lack complete estate coverage in this review. | RPF-WP-0036/0044; railiance-forge; existing CCRs; CUST-WP-0080-T03 | Pipeline writer scope and job identity, per-store namespace/path isolation, refresh/deletion semantics, consumer adoption, independently governed encryption keys |
| G12 | CI credential authority, Kubernetes delivery-copy lifecycle and at-rest protection lack complete estate coverage. Forge metadata shows Actions enabled on 165 repositories and zero protected-branch rules; this does not establish workflow execution or required checks. | RPF-WP-0036/0044; railiance-forge; existing CCRs; CUST-WP-0080-T03 | Pipeline writer scope and job identity, per-store namespace/path isolation, refresh/deletion semantics, consumer adoption, independently governed encryption keys |
| G13 | PDP authenticity is separate from digest binding. FLEX-WP-0024 implements optional signatures; Secrets Engine still lacks independently anchored verification. Its reproduced redirect/proxy credential forwarding defects are now fixed in source (675 tests pass, one skipped). Native signer/consumer acceptance remains open. | SECRETS-WP-0014 T01 done; T02/T03 own trust admission, signed consumer enforcement and native verification. CUST-WP-0080-T03 tracks estate coverage | Independently trusted key or authenticated channel, configured producer, consumer verification, forged/altered/unknown-key/unsigned-downgrade refusals and key-rotation evidence |
G01 source repair is deployed; authenticated preview/U08 remains open. G02 and G03 require existing owner
@ -103,12 +103,14 @@ acceptance remain open. [Activation receipt](evidence/2026-10-12-netkingdom-secu
All four DSM-DETECT requirements now have incomplete assessments rather than
unverified placeholders. [Receipt and exact hook inventory](evidence/2026-10-12-netkingdom-security/secret-detection.json).
G07 server baseline: the 22 reviewed repositories on railiance01 have only
G07 server baseline before activation: the 22 reviewed repositories on railiance01 had only
upstream-generated receive hooks, verified by matching all observed hashes to
[Forgejo v11.0.3 templates](https://codeberg.org/forgejo/forgejo/src/tag/v11.0.3/modules/repository/hooks.go).
No custom scanner hook is installed at that boundary. The 165 repository
directories are a discovery count, not a reviewed production denominator.
Actions/branch-protection and actual push refusal are still unverified.
At that observation no custom scanner hook was installed. The subsequent metadata reconciliation matches 165 database repositories to 165
directories. All have Actions enabled and none has a protected-branch rule. The
143 outside the initial reviewed scope remain uncovered, not exempt; enabled
Actions does not prove executed or required checks. Production admission remains
incomplete. [Metadata reconciliation](evidence/2026-10-12-netkingdom-security/forge-repository-inventory.json).
[Read-only inventory](evidence/2026-10-12-netkingdom-security/forge-secret-detection-baseline.json).
G07 introduced-history source: FORGE-WP-0006 adds a standalone forge-owned
@ -120,6 +122,18 @@ payload scanning. No production hook is activated by this source work.
Exact-binary/runtime admission, full inventory and forge frontend/transport
acceptance remain open. [Source and protocol receipt](evidence/2026-10-12-netkingdom-security/receive-secret-detection.json).
G07 activation and fresh recheck: the October 12
[activation receipt](evidence/2026-10-12-netkingdom-security/receive-hook-activation.json)
records the installed exact profile on 22 repositories. Actual SSH probes yielded
clean/blocked scanner results; the temporary independent veto prevented fixture
publication, then was removed. The October 13
[read-only recheck](evidence/2026-10-13-netkingdom-security/receive-profile-recheck.json)
confirms all expected hook hashes, preserved original hooks, executable exact
binaries and healthy service. Ordinary clean acceptance and HTTP/frontend,
restart/regeneration/new-repository coverage remain open, as do the other 143
repositories and finding-to-response acceptance. This supersedes the pre-activation
state above without claiming complete forge or DSM-DETECT closure.
## SEC DSM requirement coverage
Each numbered requirement in these families is in scope for assessment. The

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: custodian
created: "2026-10-12"
updated: "2026-10-12"
updated: "2026-10-13"
flavor: implementation
depends_on: []
state_hub_workstream_id: "dfadb19b-445e-59c6-bcd6-48e87b912c52"
@ -185,6 +185,30 @@ No production hook changed. Exact-binary admission, repository denominator,
SSH/HTTP/frontend/restart/new-repository coverage and response acceptance remain
open in FORGE-WP-0006-T02/T03 and RMGR-WP-0021-T03/T04. G07 stays open.
2026-10-12 G07 native admission: the exact adapter/scanner binaries passed
clean/detection/quarantine/tool-failure/recovery checks in disposable repositories
inside the running Forgejo image. Builtin authorization was stubbed only in this
isolated probe; no production hook changed during that probe. Receipt:
`receive-native-probe.json`. Metadata reconciliation now matches 165 database
repositories to 165 directories; none has a protected-branch rule. The initial
22 reviewed repositories pass shallow/partial/gitlink compatibility checks; the
remaining 143 are uncovered, not exempt. `forge-repository-inventory.json`
retains aggregates and reviewed identities only. An exact additive-hook activation
proposal and tested rollback are prepared as FORGE6-RECEIVE-ACTIVATION-001 under
the existing standing blue-lane authorization; outcome is recorded separately.
2026-10-13 interruption recovery: retained activation receipt proves that
FORGE6-RECEIVE-ACTIVATION-001 completed on October 12 at 17:32 UTC, after the
last progress note. All 22 exact Forgejo repositories gained the additive hook;
actual SSH probes produced clean/blocked scanner results under a temporary veto,
with probe refs/quarantined commits absent and the veto removed. A fresh read-only
inspection confirms the same pod/image, exact original and added hook hashes,
executable pinned binaries and healthy service. Evidence:
`receive-hook-activation.json` in the October 12 directory and
`docs/evidence/2026-10-13-netkingdom-security/receive-profile-recheck.json`.
Ordinary clean-push acceptance, HTTP/frontend/lifecycle coverage, the other 143
repositories and private response acceptance still need proof. G07 remains open.
## Verify native closure against every requirement
```task