Record reviewed application build source and remaining authenticated operation work

This commit is contained in:
codex 2026-10-18 00:34:06 +02:00
parent 16236ef479
commit 8951d32419
17 changed files with 1115 additions and 0 deletions

View file

@ -0,0 +1,110 @@
# Apps Forgejo release build r1
This is an isolated Apps source/package proposal for NK-WP-0048-T39. The complete
reviewed seven-path Forgejo extension was built with its frontend and embedded
assets, then assembled into a rootless OCI image archive. Apps' deployed image,
Helm values and existing deployment targets are unchanged. Canonical source,
commits, registry publication and formal owner assent were not performed.
The application profile still requires an authenticated access-engine decision;
the local claim gate is existing-case compatibility code, not a single-PDP
exception or final architecture acceptance. T37 and the T34 operational backend
remain independently open.
`owner-source/` and `apps-release-build-source.patch` propose only build tooling,
locked public release inputs and Make targets on Apps
`944b30ad63ab054cc24617e374e177d34cd572da`. Upstream source is extracted only
under `/tmp`; no second application source tree is installed in Apps. The
existing Apps Make/tools surface invokes the real upstream `frontend`,
`generate-backend` and `static-executable` targets. The immutable reviewed
extension input remains patch SHA256
`f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257`.
Owner source acknowledgment/integration/publication is separate.
The source archive, Go1.24.3 distribution and all seven reviewed source outputs
were verified against the independent review before reuse. Its source, Go tree,
module cache, original binary and evidence were not changed; Go/module inputs
were mounted read-only and build caches copied into owned workspaces. Node
v22.15.0 was downloaded from the official distribution and matched its official
SHA256. `go.mod`, `go.sum`, `package.json` and `package-lock.json` are hash-locked;
all 1,150 lockfile package records have public npm origins and integrity hashes.
Both actual installations used 1,088 applicable packages with lifecycle scripts
disabled. The decisive frontend/backend builds ran with empty HOME/config paths,
a closed environment, read-only module input, `GOPROXY=off` and a network
namespace without connectivity. npm cache acquisition was an explicit prior
public-only phase; no credential store, private config, paid/model service or
production/native endpoint was used.
Two separate source workspaces produced 628 byte-identical frontend asset files,
four byte-identical generated bindata source files and the same 110,936,928-byte
static executable:
`sha256:4df429454b0289c6df76d7fd95d41394ebc286191809349b2c1e655b6be494e4`
The actual executable exposed the implemented CLI flag and extracted every one
of its 2,234 public/options/template files with exact source byte equality,
including generated JS/CSS/fonts/licenses. This verification mounted **no source
tree, asset tree, host libraries or host configuration**: only the static binary
and an empty output directory were available in a network/PID-isolated sandbox.
A filesystem asset fallback could not pass. ELF inspection found no dynamic
interpreter. The retained glibc/SQLite optional `dlopen` linker diagnostic is not
represented as a production SQLite-extension or whole-service runtime proof.
The pinned public build-only runtime base is official Forgejo 11.0.3-rootless,
linux/amd64 manifest
`sha256:41649dff5311664097d29b4d80620403f0b27e7c0eee0b8af79b132a37f3807b`
(index `sha256:691657c7e64af7730a2e885e6d022cf16ae60724931c5392bd61838afadcaeba`).
Its manifest/config digests were checked independently. Local Docker assembly
used only that base, the verified executable and fixed provenance labels, with
no RUN directives, privileged container, host/secret mount, deployment tag or
push. Export verification checks the entire original base layer prefix,
rootless user/entrypoint/environment/paths/volumes and exact final binary bytes.
The final OCI image manifest is
`sha256:9d12779f0936b9ccdbde402a9869eaad8bb91ba724d579b6c2983e8e58dabf96`;
its config digest is
`sha256:e9e81da43c5ea6895a95b6304337a40874e3275833be5f21fc6ffc104f79a2af`.
Two no-cache OCI builds produced identical manifest/config and identical archive
bytes: `sha256:e0e74653321383e133485191f0ac5af53aafb065fb5809e20ede2808cec91539`.
These are local build outputs, not an accepted deployment selection. The final
OCI archive was not loaded as a runtime image or published. Prototype untagged
images are retained locally as build evidence only.
`evidence/` retains input/proof/output digests and local artifact paths. Large
source/cache/binary/image artifacts remain under the recorded `/tmp` paths,
including `/tmp/apps-forgejo-release-repro-r1/image.oci.tar`; they are not placed in
canonical source or published. Public registry metadata/base acquisition used
anonymous protocol access with an empty Docker config; no existing private
credential or HOME configuration was loaded. Container assembly/export uses
only the explicit local Unix socket. The source compiler toolchain/sysroot is
scoped to the recorded Linux amd64 review environment; a different host/compiler
or architecture is a different input revision, not an automatic fallback.
The same trial retains its predecessors and refinements. Upstream Make's
`GOFLAGS := -v` overrode environment-only trimpath flags; the final recipe passes
flags explicitly on Make's command line. File **and directory** timestamps are
normalised for bindata. The initial extraction harness omitted the CLI's required
`**` pattern; its failure is retained. Docker29's containerd image store rejected
export by the config digest from `--iidfile`; the image build had succeeded.
That exact prototype manifest was resolved and exported without rebuilding.
A no-cache repeat then exposed varying COPY parent-directory timestamps. The
BuildKit primary-source remedy is `rewrite-timestamp=true`; direct image load
conflicts with unpack on this engine, so the final recipe directly exports OCI.
Its image epoch is the maximum of the source epoch and rounded-up immutable base
creation time, preserving the complete original base layer prefix. Failed repeat
and unpack records are retained. These are recorded
source/build refinements, not extra native trials, approvals or successes. No
build was restarted because an observation call timed out.
[SECRET-INPUT-PROPOSAL.md](SECRET-INPUT-PROPOSAL.md) gives the concrete separate
CLI/private-file/chart-helper change required to avoid runtime `--secret` argv.
It is **not implemented or admitted** by this seven-path build. In particular,
a new `secretFile` key alone would still trigger the current chart's automatic
`--secret` insertion. No secret value was used in any agent/build argument.
The actual operation/inverse, durable authenticated journal, exact persisted
application before/post source state, all-writer exclusion and current sessions
remain T34 work. Helm omission/rollback still does not remove persisted OAuth
sources; image downgrade before verified application-source inverse is unsafe.
Linked users/external logins must never be removed to force deletion.
See `owner-source/build/forgejo/README.md` for the exact prepare/acquire/build/
verify/container commands and refusal behavior. This packet supplies no native
placement, capacity, rollout, group/login probe, secret-read or authority grant.

View file

@ -0,0 +1,13 @@
{
"two_independent_source_workspaces": true,
"binary_byte_identical": true,
"binary_sha256": "4df429454b0289c6df76d7fd95d41394ebc286191809349b2c1e655b6be494e4",
"bytes": 110936928,
"generated_bindata_sources_identical": {
"modules/public/bindata.go": "b01dc648ebe2654648ed1d59aa5691cc9df6d6c91dcf8de53c61df5eac5159fb",
"modules/options/bindata.go": "007db55c390fcbc4d48fffba7c5eeb5379950011b02f1784e9caa5bb32c44ec6",
"modules/templates/bindata.go": "e2fb15b4a237bae1e8a4cf455be8a2d77e6fe5b6e803f518ba20198bb0712bb1",
"modules/migration/bindata.go": "de07bf72d462550a31f0e00e8b4163f3b3448778eda2b35e43af5ef075aebbff"
},
"same_trial_refinements_not_new_native_successes": true
}

View file

@ -0,0 +1,15 @@
{
"two_no_cache_OCI_builds": true,
"identical_image_manifest_and_config": true,
"digests": {
"containerimage.digest": "sha256:9d12779f0936b9ccdbde402a9869eaad8bb91ba724d579b6c2983e8e58dabf96",
"containerimage.config.digest": "sha256:e9e81da43c5ea6895a95b6304337a40874e3275833be5f21fc6ffc104f79a2af"
},
"oci_archive_1_sha256": "e0e74653321383e133485191f0ac5af53aafb065fb5809e20ede2808cec91539",
"oci_archive_2_sha256": "e0e74653321383e133485191f0ac5af53aafb065fb5809e20ede2808cec91539",
"oci_archive_bytes_identical": true,
"source_binary_independently_reproduced": true,
"all_original_base_layers_preserved": true,
"no_registry_publication": true,
"no_deployment_selection": true
}

View file

@ -0,0 +1,40 @@
{
"schema": "custodian.apps-forgejo-release-build-source.v1",
"apps_base": "944b30ad63ab054cc24617e374e177d34cd572da",
"canonical_public_files_unchanged": {
"Makefile": "a319e264e6f04378f6b3d2c7781860fc4bac1abdb248cffa8c26065e08f2f290",
"helm/forgejo-values.yaml": "cf87a3dccd666bf8870619755afac4af64fc0bee77b0f0ea54718d6384b70d4f",
"helm/forgejo-registry-values.yaml": "a38f551734843c6367448f267c7376b1aeee010927a49690fdd7c1471e0ae450"
},
"reviewed_patch_sha256": "f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257",
"reviewed_source_and_original_binary_unchanged": true,
"earlier_packets": {
"apps-chart-projection-r1": {
"frozen_entries_verified": 33,
"metadata_original_reconstructed": true
},
"apps-execution-backend-r1": {
"frozen_entries_verified": 8,
"metadata_original_reconstructed": false
},
"forgejo-required-claim-values-r1": {
"frozen_entries_verified": 33,
"metadata_original_reconstructed": false
}
},
"metadata_refinement_proof": "evidence/earlier-metadata-observation.json",
"inputs_lock_sha256": "29f329b204a2a5f72084b50d59e8445486ff4799450097c6f3908c74e87a233a",
"owner_patch_sha256": "f0bcb2903592874d355e2a403de0c22aeda79b00070f30e7ea02b45106dd67fa",
"owner_postimages": {
"Makefile": "572d36e2dd3dee6321a5f6c4726f83991031672be5eb3480ae6173f8ce50ccdd",
"build/forgejo/README.md": "c3d37b8e62a99c351b8630a31f875fb8f4afbf54ec2488460066c88148f76fa8",
"build/forgejo/inputs.lock.json": "29f329b204a2a5f72084b50d59e8445486ff4799450097c6f3908c74e87a233a",
"build/forgejo/required-claim-values.patch": "f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257",
"build/forgejo/runtime-base-config.json": "bc5a3df111729582faadebd01d126ba769e2b65d0c62f306f6bc79f4e562452b",
"tools/forgejo-release-build.py": "6ecb2cf4bd700b6d859d70024904cee7a8dd32d8cb0d43ada92ee5279f43994e"
},
"exact_patch_applied_and_all_postimages_verified": true,
"source_integration": false,
"formal_owner_assent": false,
"commits_or_publication": false
}

View file

@ -0,0 +1,21 @@
{
"schema": "custodian.apps-forgejo-release-build-validation.v1",
"task": "NK-WP-0048-T39 source/local build preparation",
"full_frontend_and_embedded_static_backend": true,
"frontend_reproduction": "evidence/frontend-reproduction.json",
"binary_reproduction": "evidence/binary-reproduction.json",
"bare_binary_asset_verification": "evidence/verification.json",
"deterministic_oci_reproduction": "evidence/container-reproduction.json",
"final_container": "evidence/container-result.json",
"patch_apply_and_all_six_postimages_exact": true,
"canonical_deployed_defaults_unchanged": true,
"independent_review_source_and_binary_unchanged": true,
"prior_failures_preserved": true,
"secret_input_proposal_implemented": false,
"T37_architecture_acceptance": false,
"T34_native_backend_journal_exclusion_inverse_sessions": false,
"authenticated_access_engine_decision_still_required": true,
"native_or_credential_or_paid_model_calls": false,
"deployment_selection_or_registry_publication": false,
"formal_owner_assent": false
}

View file

@ -0,0 +1,31 @@
{
"recorded_at": "2026-10-17T22:03:08.633215+00:00",
"same_trial": true,
"apps_base": "git:944b30ad63ab054cc24617e374e177d34cd572da",
"predecessor_patch_sha256": "sha256:f0bcb2903592874d355e2a403de0c22aeda79b00070f30e7ea02b45106dd67fa",
"patch_sha256": "sha256:b7ad8f8fd908532800f4e7eb0f7ad85d77e21a0b729cb5115ade3d5fe3e4acd8",
"owner_postimages": {
"Makefile": "sha256:572d36e2dd3dee6321a5f6c4726f83991031672be5eb3480ae6173f8ce50ccdd",
"build/forgejo/README.md": "sha256:c3d37b8e62a99c351b8630a31f875fb8f4afbf54ec2488460066c88148f76fa8",
"build/forgejo/inputs.lock.json": "sha256:29f329b204a2a5f72084b50d59e8445486ff4799450097c6f3908c74e87a233a",
"build/forgejo/required-claim-values.patch": "sha256:f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257",
"build/forgejo/runtime-base-config.json": "sha256:bc5a3df111729582faadebd01d126ba769e2b65d0c62f306f6bc79f4e562452b",
"tools/forgejo-release-build.py": "sha256:7e28d9bd5adefaece96eb1d31a23e128ec8f448958e45d22467bf7acf476a9ba"
},
"refinement": "Only --unshare-pid added in build sandbox. Original full build/OCI proof and adverse process-visibility canary remain historical evidence.",
"source_code_changed": [
"tools/forgejo-release-build.py:sandbox"
],
"patch_apply_and_postimages_verified": true,
"scratch": "/tmp/apps-build-r2-patch-verified-qpaw0ol9",
"actual_full_r2_build_performed": false,
"existing_full_build_proof": "../apps-forgejo-release-build-r1/evidence/",
"canonical_edits": false,
"native_actions": false,
"review_status": "pending exact namespace-fix review",
"patch_generation_refinement": {
"failed_patch_sha256": "sha256:64c86ac86cf78715535b096cbf47204586a5c26b7e9c993cce2c136cb5ae2cee",
"outcome": "Patch application returned success but exact postimage guard refused runtime-base-config.json; generated patch lacked no-final-newline marker and appended next diff header. No candidate or canonical source changed.",
"correction": "Derived exact original already-verified six-path patch, changed only existing sandbox line; all six postimages byte-identical to intended outputs."
}
}

View file

@ -0,0 +1,29 @@
{
"public_synthetic_fixture_only": true,
"outer_PID_and_network_namespace_prevent_real_host_visibility": true,
"shipped_sandbox": {
"returncode": 1,
"stdout": "",
"stderr": "Traceback (most recent call last):\n File \"<string>\", line 1, in <module>\n File \"/usr/lib/python3.12/pathlib.py\", line 862, in exists\n self.stat(follow_symlinks=follow_symlinks)\n File \"/usr/lib/python3.12/pathlib.py\", line 842, in stat\n return os.stat(self, follow_symlinks=follow_symlinks)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nPermissionError: [Errno 13] Permission denied: '/proc/2/root/tmp/review/outside-build-workspace-synthetic.txt'\n"
},
"same_command_with_only_unshare_pid_added": {
"returncode": 0,
"stdout": "False\nDENIED\n",
"stderr": ""
},
"shipped_sandbox_proc_parent_root_escape": false,
"unshare_pid_control_denies_fixture": true,
"shipped_sandbox_host_process_cmdline": {
"returncode": 0,
"stdout": "b'/usr/bin/python3\\x00-I\\x00-c\\x00import sys;sys.stdin.read()\\x00PUBLIC-SYNTHETIC-ARGV-CANARY\\x00'\n",
"stderr": ""
},
"with_unshare_pid_host_process_cmdline": {
"returncode": 0,
"stdout": "DENIED\n",
"stderr": ""
},
"outside_process_argv_visible": true,
"unshare_pid_control_denies_argv": true,
"helper_terminal": 0
}

View file

@ -0,0 +1,41 @@
"""Synthetic-only test of the shipped sandbox's proc visibility inside outer PID isolation."""
import importlib.util,json,os,subprocess
from pathlib import Path
out=Path('/tmp/review')
fixture=out/'outside-build-workspace-synthetic.txt'
fixture.write_text('PUBLIC-SYNTHETIC-BOUNDARY-CANARY\n')
work=out/'boundary-work';(work/'source').mkdir(parents=True);(work/'cache').mkdir()
spec=importlib.util.spec_from_file_location('recipe','/proposal/owner-source/tools/forgejo-release-build.py')
m=importlib.util.module_from_spec(spec);spec.loader.exec_module(m)
env={'PATH':'/usr/bin:/bin','HOME':str(work/'home'),'GOMODCACHE':str(work/'cache')}
base=m.sandbox(work,env)
target='/proc/'+str(os.getpid())+'/root'+str(fixture)
command=['/usr/bin/python3','-I','-c','import pathlib,sys; p=pathlib.Path(sys.argv[1]); print(p.exists()); print(p.read_text() if p.exists() else "DENIED")',target]
def run(args):
p=subprocess.run(args,env={'PATH':'/usr/bin:/bin','HOME':'/tmp/home'},capture_output=True,text=True)
return {'returncode':p.returncode,'stdout':p.stdout,'stderr':p.stderr}
original=run(base+command)
corrected=run(base[:1]+['--unshare-pid']+base[1:]+command)
helper=subprocess.Popen(['/usr/bin/python3','-I','-c','import sys;sys.stdin.read()',
'PUBLIC-SYNTHETIC-ARGV-CANARY'],stdin=subprocess.PIPE,
env={'PATH':'/usr/bin:/bin','HOME':'/tmp/home'})
try:
cmdline=['/usr/bin/python3','-I','-c',
'import pathlib,sys; p=pathlib.Path(sys.argv[1]); print(p.read_bytes() if p.exists() else "DENIED")',
'/proc/'+str(helper.pid)+'/cmdline']
argv_original=run(base+cmdline)
argv_corrected=run(base[:1]+['--unshare-pid']+base[1:]+cmdline)
finally:
helper.stdin.close()
helper.wait(timeout=10)
result={'public_synthetic_fixture_only':True,'outer_PID_and_network_namespace_prevent_real_host_visibility':True,
'shipped_sandbox':original,'same_command_with_only_unshare_pid_added':corrected,
'shipped_sandbox_proc_parent_root_escape': 'PUBLIC-SYNTHETIC-BOUNDARY-CANARY' in original['stdout'],
'unshare_pid_control_denies_fixture':'PUBLIC-SYNTHETIC-BOUNDARY-CANARY' not in corrected['stdout'],
'shipped_sandbox_host_process_cmdline':argv_original,
'with_unshare_pid_host_process_cmdline':argv_corrected,
'outside_process_argv_visible':'PUBLIC-SYNTHETIC-ARGV-CANARY' in argv_original['stdout'],
'unshare_pid_control_denies_argv':'PUBLIC-SYNTHETIC-ARGV-CANARY' not in argv_corrected['stdout'],
'helper_terminal':helper.returncode}
(out/'proc-boundary-result.json').write_text(json.dumps(result,indent=2)+'\n')
print(json.dumps(result,indent=2))

View file

@ -0,0 +1,57 @@
{
"schema": "custodian.apps-release-independent-review.v1",
"reviewed_on": "2026-10-18",
"verdict": "changes-required",
"source_integration_accepted": false,
"candidate_patch_sha256": "f0bcb2903592874d355e2a403de0c22aeda79b00070f30e7ea02b45106dd67fa",
"candidate_map_sha256": "ec499038fa9a1e612bb81ed63bd67dad2ca52a178bb7bcb89a33bb64832880bb",
"findings": [
{
"id": "APPSBUILD-R1-F01",
"severity": "medium",
"blocks_source_integration": true,
"path": "tools/forgejo-release-build.py",
"line": 46,
"problem": "Build sandbox exposes unrelated host process command lines through /proc because it does not create a PID namespace.",
"evidence": "proc-boundary-result.json: outside_process_argv_visible=true; unshare_pid_control_denies_argv=true",
"scope": "Actual synthetic unrelated argv read, not a demonstrated host filesystem escape or real credential exposure.",
"requested_correction": "Add --unshare-pid to sandbox(); preserve r1 and exact adverse evidence, publish separate revised source packet."
}
],
"frozen_entries_verified": 71,
"exact_six_path_pre_postimage_check": true,
"accepted_prior_backend_source_review_bound": true,
"fresh_bare_binary_verifier": "PASS (2234 files exact, new CLI, no ELF interpreter)",
"seven_adverse_input_controls": "PASS",
"retained_full_build_artifacts_rehashed": "PASS (2 workspaces, 628 frontend files each, 4 bindata outputs each, exact same binary)",
"OCI_independent_offline_content_and_provenance_checks": "PASS (all descriptors, blob hashes, diff_ids, original base prefix, rootless config, labels, binary, mode, timestamps)",
"full_build_repeated_by_reviewer": false,
"OCI_build_repeated_by_reviewer": false,
"prior_artifacts_represent_original_r1_profile": true,
"reviewer_failed_outcome_preserved": "offline-attempt1.json/.log; offline-results-attempt1.json; review-offline-attempt1.py; upper-bound timestamp assertion corrected only in reviewer harness",
"canonical_Apps_unchanged": "944b30ad63ab054cc24617e374e177d34cd572da",
"candidate_unchanged": true,
"reviewer_writes": "Only this review packet and private /tmp public-fixture workspaces; root original eight dirty paths not touched.",
"network_native_registry_docker_credential_model_operations": false,
"formal_owner_assent": false,
"architecture_acceptance": false,
"deployment_authority": false,
"existing_operational_gaps": [
"authenticated Access Engine decision",
"private runtime secret input (not implemented)",
"owner integration and image admission/publication",
"exact type/case/descriptor re-freeze",
"current operation and inverse sessions",
"durable authenticated journal",
"authoritative persisted application before/post/current state",
"all release/application writer exclusion",
"browser/group/login proofs",
"capacity and rollout"
],
"execution_status": {
"all_owned_handles_terminal": true,
"live_handles": [],
"helper_terminal_returncode": 0,
"native_trial_started": false
}
}

View file

@ -0,0 +1,132 @@
{
"APPSBUILD-R1-F01_closed_for_exact_r2": true,
"exact_refinement": {
"old_review_and_inputs_preserved": true,
"only_change": "sandbox adds --unshare-pid",
"six_paths": 6,
"unchanged_locks_archives_patch_release_and_runtime_base": true
},
"full_r2_build_or_image_build_performed": false,
"namespace_fix": {
"r1": {
"argv": [
"bwrap",
"--unshare-net",
"--ro-bind",
"/usr",
"/usr",
"--ro-bind",
"/lib",
"/lib",
"--ro-bind",
"/lib64",
"/lib64",
"--symlink",
"usr/bin",
"/bin",
"--proc",
"/proc",
"--dev",
"/dev",
"--tmpfs",
"/tmp",
"--bind",
"/tmp/review/sandbox-work",
"/tmp/review/sandbox-work",
"--ro-bind",
"/tmp/review/sandbox-work/cache",
"/tmp/review/sandbox-work/cache",
"--chdir",
"/tmp/review/sandbox-work/source",
"--",
"env",
"-i",
"PATH=/usr/bin:/bin",
"HOME=/tmp/review/sandbox-work/empty-home",
"GOMODCACHE=/tmp/review/sandbox-work/cache",
"LC_ALL=C",
"/usr/bin/python3",
"-I",
"-c",
"import pathlib,sys,os,json; p=pathlib.Path(sys.argv[1]); print(json.dumps({\"parent_argv\": p.read_text() if p.exists() else \"DENIED\", \"self_pid\":os.getpid(),\"pid_namespace\":os.readlink(\"/proc/self/ns/pid\"),\"cwd\":os.getcwd(),\"host_home_present\":pathlib.Path(\"/home/worsch\").exists(),\"docker_socket_present\":pathlib.Path(\"/var/run/docker.sock\").exists(),\"environment\":dict(os.environ)}))",
"/proc/5/cmdline"
],
"result": {
"cwd": "/tmp/review/sandbox-work/source",
"docker_socket_present": false,
"environment": {
"GOMODCACHE": "/tmp/review/sandbox-work/cache",
"HOME": "/tmp/review/sandbox-work/empty-home",
"LC_ALL": "C",
"PATH": "/usr/bin:/bin"
},
"host_home_present": false,
"parent_argv": "/usr/bin/python3\u0000-I\u0000-c\u0000import sys;sys.stdin.read()\u0000PUBLIC-R2-SYNTHETIC-ARGV-CANARY\u0000",
"pid_namespace": "pid:[4026532379]",
"self_pid": 7
}
},
"r2": {
"argv": [
"bwrap",
"--unshare-net",
"--unshare-pid",
"--ro-bind",
"/usr",
"/usr",
"--ro-bind",
"/lib",
"/lib",
"--ro-bind",
"/lib64",
"/lib64",
"--symlink",
"usr/bin",
"/bin",
"--proc",
"/proc",
"--dev",
"/dev",
"--tmpfs",
"/tmp",
"--bind",
"/tmp/review/sandbox-work",
"/tmp/review/sandbox-work",
"--ro-bind",
"/tmp/review/sandbox-work/cache",
"/tmp/review/sandbox-work/cache",
"--chdir",
"/tmp/review/sandbox-work/source",
"--",
"env",
"-i",
"PATH=/usr/bin:/bin",
"HOME=/tmp/review/sandbox-work/empty-home",
"GOMODCACHE=/tmp/review/sandbox-work/cache",
"LC_ALL=C",
"/usr/bin/python3",
"-I",
"-c",
"import pathlib,sys,os,json; p=pathlib.Path(sys.argv[1]); print(json.dumps({\"parent_argv\": p.read_text() if p.exists() else \"DENIED\", \"self_pid\":os.getpid(),\"pid_namespace\":os.readlink(\"/proc/self/ns/pid\"),\"cwd\":os.getcwd(),\"host_home_present\":pathlib.Path(\"/home/worsch\").exists(),\"docker_socket_present\":pathlib.Path(\"/var/run/docker.sock\").exists(),\"environment\":dict(os.environ)}))",
"/proc/5/cmdline"
],
"result": {
"cwd": "/tmp/review/sandbox-work/source",
"docker_socket_present": false,
"environment": {
"GOMODCACHE": "/tmp/review/sandbox-work/cache",
"HOME": "/tmp/review/sandbox-work/empty-home",
"LC_ALL": "C",
"PATH": "/usr/bin:/bin"
},
"host_home_present": false,
"parent_argv": "DENIED",
"pid_namespace": "pid:[4026532441]",
"self_pid": 2
}
}
},
"patch_exact_six_postimages": true,
"r1_artifact_evidence_retains_r1_profile": true,
"synthetic_helper_terminal_returncode": 0
}

View file

@ -0,0 +1,50 @@
{
"schema": "custodian.apps-release-independent-review.v1",
"reviewed_on": "2026-10-18",
"verdict": "accept",
"source_integration_accepted": true,
"candidate_patch_sha256": "b7ad8f8fd908532800f4e7eb0f7ad85d77e21a0b729cb5115ade3d5fe3e4acd8",
"candidate_source_refinement_sha256": "1e96b866284908299b6363c0ddd1363181bd8513ae63eb178967f636de008972",
"predecessor_review": "../apps-release-independent-review-r1/review.json",
"predecessor_review_sha256": "df2c23df953e1d4c10bd3abd7aea350cc33d8bbfdb2a99d92a436feba0946f73",
"predecessor_review_map_sha256": "9a2266ffa638ce771a5cc014e93b53c8e465270d351c502cf42c9c586409f7c9",
"same_trial": true,
"findings": [],
"closed_findings": [
{
"id": "APPSBUILD-R1-F01",
"correction": "Only --unshare-pid added to exact build sandbox",
"evidence": "results.json: exact r1 synthetic outside-process argv readable, exact r2 returns DENIED, new PID namespace inode verified."
}
],
"exact_patch_pre_postimages": true,
"owner_postimages": {
"Makefile": "sha256:572d36e2dd3dee6321a5f6c4726f83991031672be5eb3480ae6173f8ce50ccdd",
"build/forgejo/README.md": "sha256:c3d37b8e62a99c351b8630a31f875fb8f4afbf54ec2488460066c88148f76fa8",
"build/forgejo/inputs.lock.json": "sha256:29f329b204a2a5f72084b50d59e8445486ff4799450097c6f3908c74e87a233a",
"build/forgejo/required-claim-values.patch": "sha256:f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257",
"build/forgejo/runtime-base-config.json": "sha256:bc5a3df111729582faadebd01d126ba769e2b65d0c62f306f6bc79f4e562452b",
"tools/forgejo-release-build.py": "sha256:7e28d9bd5adefaece96eb1d31a23e128ec8f448958e45d22467bf7acf476a9ba"
},
"only_source_delta": "tools/forgejo-release-build.py:sandbox adds --unshare-pid",
"build_inputs_and_commands_unchanged": true,
"prior_r1_source_and_review_maps_reverified": true,
"prior_full_frontend_bindata_binary_OCI_proof": "Frozen r1 artifacts and profile only; retained independent byte/content verification in r1 review.",
"full_r2_build_performed": false,
"full_r2_image_build_performed": false,
"r2_binary_or_image_reproduction_claimed": false,
"expensive_rebuild_required_for_bounded_source_acceptance": false,
"reviewer_failure_preserved": "execution-attempt1.json, namespace-review-attempt1.log, review-namespace-refinement-attempt1.py: incorrect PID1 child assertion; corrected to namespace inode inequality. No candidate change.",
"candidate_or_canonical_changed_by_reviewer": false,
"formal_owner_assent": false,
"architecture_acceptance": false,
"image_admission": false,
"deployment_authority": false,
"existing_operational_gaps_inherited": "../apps-release-independent-review-r1/review.json:existing_operational_gaps (no gate added or waived)",
"network_native_docker_registry_credential_model_operations": false,
"execution_status": {
"all_owned_handles_terminal": true,
"live_handles": [],
"synthetic_helper_returncode": 0
}
}

View file

@ -0,0 +1,96 @@
"""Integrate only exact independently accepted build source and owner tasks."""
from pathlib import Path
import argparse
import hashlib
import json
import re
import subprocess
import sys
HERE = Path(__file__).resolve().parent
ROOT = Path('/home/worsch/railiance-apps')
PACKET = HERE.parent / 'apps-forgejo-release-build-r2'
OLD_PACKET = HERE.parent / 'apps-forgejo-release-build-r1'
BASE = '944b30ad63ab054cc24617e374e177d34cd572da'
PLAN = 'workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md'
def sha(data):
return hashlib.sha256(data).hexdigest()
def git(*args):
return subprocess.check_output(['git', '-C', str(ROOT), *args],
stderr=subprocess.PIPE, timeout=45).decode().strip()
parser = argparse.ArgumentParser()
parser.add_argument('--review', type=Path, required=True)
parser.add_argument('--review-sha256', required=True)
args = parser.parse_args()
assert sha(args.review.read_bytes()) == args.review_sha256.removeprefix('sha256:')
review = json.loads(args.review.read_text())
assert review['source_integration_accepted'] is True
assert review['verdict'] == 'accept'
refinement = json.loads((PACKET / 'source-refinement.json').read_text())
assert sha((PACKET / 'source-refinement.json').read_bytes()) == review['candidate_source_refinement_sha256'].removeprefix('sha256:')
assert refinement['owner_postimages'] == review['owner_postimages']
patch_hash = sha((PACKET / 'apps-release-build-source.patch').read_bytes())
assert 'sha256:' + patch_hash == refinement['patch_sha256']
assert review['candidate_patch_sha256'].removeprefix('sha256:') == patch_hash
assert git('rev-parse', 'HEAD') == BASE
assert git('ls-remote', 'origin', 'refs/heads/main').split()[0] == BASE
assert set(git('diff', '--name-only', 'HEAD').splitlines()) <= {'.custodian-brief.md', 'WORK-RECORDS.md'}
originals = {n: {'worktree_sha256': sha((ROOT / n).read_bytes()),
'index': git('ls-files', '--stage', '--', n)}
for n in ('.custodian-brief.md', 'WORK-RECORDS.md') if (ROOT / n).exists()}
inventory = json.loads((OLD_PACKET / 'source-inventory.json').read_text())
for n, expected in inventory['canonical_public_files_unchanged'].items():
assert sha((ROOT / n).read_bytes()) == expected, n
for n, expected in refinement['owner_postimages'].items():
assert sha((PACKET / 'owner-source' / n).read_bytes()) == expected.removeprefix('sha256:'), n
if n == 'Makefile':
assert (ROOT / n).read_bytes() == (OLD_PACKET / 'preimages' / n).read_bytes()
else:
assert not (ROOT / n).exists(), n
assert (ROOT / PLAN).read_bytes() == (HERE / 'preimage.md').read_bytes()
plans = {str(p.relative_to(ROOT)): sha(p.read_bytes()) for p in (ROOT / 'workplans').rglob('*.md')}
before_blocks = re.findall(r'```task\n.*?```', (ROOT / PLAN).read_text(), re.S)
candidate = (HERE / 'workplan.md').read_text()
assert len(before_blocks) == 5 and all(b in candidate for b in before_blocks)
sys.path.insert(0, '/home/worsch/repo-manager/src')
from repo_manager.identifiers import ensure_missing_work_record_identifiers
preview = ensure_missing_work_record_identifiers(ROOT, execute=False)
assert preview['ok'] and not preview['assignments'] and not preview['files_changed']
for n in refinement['owner_postimages']:
target = ROOT / n
target.parent.mkdir(parents=True, exist_ok=True)
target.write_bytes((PACKET / 'owner-source' / n).read_bytes())
(ROOT / PLAN).write_text(candidate)
preview = ensure_missing_work_record_identifiers(ROOT, execute=False)
(HERE / 'identifier-preview.json').write_text(json.dumps(preview, indent=2) + '\n')
assert preview['ok'] and preview['files_changed'] == [PLAN] and len(preview['assignments']) == 4
assigned = ensure_missing_work_record_identifiers(ROOT, execute=True)
(HERE / 'identifier-assignment.json').write_text(json.dumps(assigned, indent=2) + '\n')
assert assigned['ok'] and assigned['files_changed'] == [PLAN]
for n, expected in plans.items():
if n != PLAN:
assert sha((ROOT / n).read_bytes()) == expected, n
for n, state in originals.items():
assert sha((ROOT / n).read_bytes()) == state['worktree_sha256']
assert git('ls-files', '--stage', '--', n) == state['index']
assert all(b in (ROOT / PLAN).read_text() for b in before_blocks)
files = [{'path': n, 'sha256': sha((ROOT / n).read_bytes())}
for n in [*refinement['owner_postimages'], PLAN]]
cfg = {'owner': 'railiance-apps', 'base_revision': BASE,
'message': 'Add pinned Forgejo release build path and track operational integration', 'files': files}
(HERE / 'publication-inputs.json').write_text(json.dumps(cfg, indent=2) + '\n')
(HERE / 'source-application.json').write_text(json.dumps({
'base': 'git:' + BASE, 'review_sha256': 'sha256:' + sha(args.review.read_bytes()),
'patch_sha256': 'sha256:' + patch_hash, 'files': files,
'original_task_blocks_preserved': len(before_blocks), 'other_workplans_preserved': len(plans) - 1,
'unrelated_state': originals, 'native_actions': False,
'image_values_and_registry_values_unchanged': True,
'formal_owner_assent': False}, indent=2) + '\n')
print(json.dumps({'status': 'source_applied', 'files': len(files), 'new_task_ids': 4,
'original_task_blocks_preserved': 5, 'native_actions': False}))

View file

@ -0,0 +1,74 @@
{
"schema": "repo-manager.identifier-assignment.v1",
"ok": true,
"executed": true,
"repo": "railiance-apps",
"namespace": "helixforge",
"assignments": [
{
"kind": "task",
"record_id": "RAPPS-WP-0016-T06",
"uuid": "08ab8921-7801-5309-b84b-bc2a3ceea1e4",
"path": "workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md"
},
{
"kind": "task",
"record_id": "RAPPS-WP-0016-T07",
"uuid": "786d6584-6db1-5a10-9324-d7b94db0df94",
"path": "workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md"
},
{
"kind": "task",
"record_id": "RAPPS-WP-0016-T08",
"uuid": "4ab8a5e7-ab32-5ee2-aaf2-6da246d1b0c8",
"path": "workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md"
},
{
"kind": "task",
"record_id": "RAPPS-WP-0016-T09",
"uuid": "d3804638-c73d-5b9f-a456-4262f62f9e6b",
"path": "workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md"
}
],
"historical_invalid_identifiers": [
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I01",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-1"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I02",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-2"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I03",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-3"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I04",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-4"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I05",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-5"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I06",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-6"
},
{
"kind": "task",
"id": "RAILIANCE-WP-0004-I07",
"source": "workplans/archived/260702-railiance-apps-WP-0004-app-deployment-improvements.md#task-block-7"
}
],
"historical_identity_collisions": [],
"files_changed": [
"workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md"
]
}

View file

@ -0,0 +1,50 @@
{
"base": "git:944b30ad63ab054cc24617e374e177d34cd572da",
"review_sha256": "sha256:6f016d53a7ec9ece2f9da9686e76127c52d17066f2b3d371628832ac9537ac5c",
"patch_sha256": "sha256:b7ad8f8fd908532800f4e7eb0f7ad85d77e21a0b729cb5115ade3d5fe3e4acd8",
"files": [
{
"path": "Makefile",
"sha256": "572d36e2dd3dee6321a5f6c4726f83991031672be5eb3480ae6173f8ce50ccdd"
},
{
"path": "build/forgejo/README.md",
"sha256": "c3d37b8e62a99c351b8630a31f875fb8f4afbf54ec2488460066c88148f76fa8"
},
{
"path": "build/forgejo/inputs.lock.json",
"sha256": "29f329b204a2a5f72084b50d59e8445486ff4799450097c6f3908c74e87a233a"
},
{
"path": "build/forgejo/required-claim-values.patch",
"sha256": "f2788b3f2bf84dbc0f94e232b6c9614a864b8123c09f9e44703d50d5e1b53257"
},
{
"path": "build/forgejo/runtime-base-config.json",
"sha256": "bc5a3df111729582faadebd01d126ba769e2b65d0c62f306f6bc79f4e562452b"
},
{
"path": "tools/forgejo-release-build.py",
"sha256": "7e28d9bd5adefaece96eb1d31a23e128ec8f448958e45d22467bf7acf476a9ba"
},
{
"path": "workplans/RAPPS-WP-0016-forgejo-netkingdom-login.md",
"sha256": "0ac8db087247bf980339ef8661a26eeb817af82391e3e85038be773fe3c6fb3a"
}
],
"original_task_blocks_preserved": 5,
"other_workplans_preserved": 19,
"unrelated_state": {
".custodian-brief.md": {
"worktree_sha256": "07f96d4120b25a046a5a82a89d2d1d1c77cad380a80772a6fc0d024da2f0c4d4",
"index": "100644 1f9b6fae4362945f96aa9a2a9647be9c83d8296a 0\t.custodian-brief.md"
},
"WORK-RECORDS.md": {
"worktree_sha256": "5a426a12d26721d4839461cf3c0285b198aafe332c3152d0744e06f0ed15e010",
"index": "100644 89c6d25cfe29035a2e0ad71113c31b89338b0cc3 0\tWORK-RECORDS.md"
}
},
"native_actions": false,
"image_values_and_registry_values_unchanged": true,
"formal_owner_assent": false
}

View file

@ -0,0 +1,55 @@
{
"status": "verified",
"source_commit": "git:c29408ae6747158a639dc876e6d7492680675658",
"instance": "primary/railiance01",
"task_bindings": [
{
"record_id": "RAPPS-WP-0016-T01",
"uuid": "98004ed0-83e6-5f6e-9b18-15b8b2aec2e7",
"status": "done"
},
{
"record_id": "RAPPS-WP-0016-T02",
"uuid": "13cd3aec-c87d-5d3f-a421-39d8ff131edd",
"status": "wait"
},
{
"record_id": "RAPPS-WP-0016-T03",
"uuid": "81f072aa-c316-511e-a2cd-21dd1b1d0a00",
"status": "wait"
},
{
"record_id": "RAPPS-WP-0016-T04",
"uuid": "32c54737-c40f-5fde-9b91-163f8dcb0068",
"status": "wait"
},
{
"record_id": "RAPPS-WP-0016-T05",
"uuid": "728786c9-f1f9-5983-a6a4-dea21faf67f5",
"status": "wait"
},
{
"record_id": "RAPPS-WP-0016-T06",
"uuid": "08ab8921-7801-5309-b84b-bc2a3ceea1e4",
"status": "done"
},
{
"record_id": "RAPPS-WP-0016-T07",
"uuid": "786d6584-6db1-5a10-9324-d7b94db0df94",
"status": "progress"
},
{
"record_id": "RAPPS-WP-0016-T08",
"uuid": "4ab8a5e7-ab32-5ee2-aaf2-6da246d1b0c8",
"status": "progress"
},
{
"record_id": "RAPPS-WP-0016-T09",
"uuid": "d3804638-c73d-5b9f-a456-4262f62f9e6b",
"status": "todo"
}
],
"original_five_task_blocks_preserved": true,
"reviewed_build_postimages_match": true,
"native_changes": false
}

View file

@ -0,0 +1,259 @@
---
id: RAPPS-WP-0016
type: workplan
title: "Forgejo sign-in through NetKingdom, before the forge closes"
domain: infotech
repo: railiance-apps
status: active
flavor: implementation
owner: claude-code
topic_slug: railiance
created: "2026-10-08"
updated: "2026-10-18"
depends_on:
- KEY-WP-0038
related_repos:
- prj-forgejo-org-refactor
- key-cape
- railiance-platform
state_hub_workstream_id: "f6b1d6f6-0abb-5774-87b9-bf3cfb640a3b"
---
# RAPPS-WP-0016 - Forgejo sign-in through NetKingdom, before the forge closes
## Why
`forgejo.coulomb.social` is closing: private by default, no anonymous access
(prj-forgejo-org-refactor ORGREF-WP-0002, decision
`decisions/forge-visibility-policy.md`). The founder's condition is that sign-in
runs through NetKingdom first. railiance-apps owns the Forgejo Helm release
(`docs/forgejo-on-railiance01.md`: S5 Helm release, ingress, operator Makefile),
so the Forgejo side lands here. This plan is ORGREF-WP-0002-T05. The NetKingdom
side is key-cape `KEY-WP-0038`.
## Boundaries
- **Founder guardrail:** tighten gradually; never lock anyone out; never risk
assets; never reach a state that is hard to repair. Every step keeps the
current sign-in path working until the new one is proven.
- **No visibility change** in this plan. Repositories, packages and
`REQUIRE_SIGNIN_VIEW` are ORGREF-WP-0002-T08.
- **Configuration in git.** The authentication source is declared in
`helm/forgejo-values.yaml` (`gitea.oauth`), with its secret drawn from an
ExternalSecret over OpenBao. No click-ops, and no secret value in git.
- Open registration is already disabled (`service.DISABLE_REGISTRATION: true`).
This plan keeps it that way.
## Tasks
```task
id: RAPPS-WP-0016-T01
status: done
priority: high
state_hub_task_id: "98004ed0-83e6-5f6e-9b18-15b8b2aec2e7"
```
### T01 — Make the local administrator a sealed break-glass
Before anything about sign-in changes: confirm the local administrator account
works, keep its credential only in OpenBao, and document recovery (who, how,
where it is logged) in `docs/forgejo-on-railiance01.md`. Verify one break-glass
sign-in and record it without the credential.
Acceptance: a recorded break-glass sign-in, with the recovery path written down.
This is the "never lock ourselves out" floor for every later step.
Done 2026-10-17: founder sealed `forgejo_admin` into OpenBao
`platform/workloads/forgejo/break-glass-admin` (version 1) and verified a local
sign-in (HTTP 200, site admin): `docs/evidence/2026-10-17-forgejo-breakglass-signin.json`.
Recovery path: `docs/forgejo-on-railiance01.md` § Break-glass administrator.
```task
id: RAPPS-WP-0016-T02
status: wait
depends_on: [RAPPS-WP-0016-T01, KEY-WP-0038-T02]
blocking_reason: "Break-glass done (T01); needs the NetKingdom client registered with its secret in custody (KEY-WP-0038-T02)."
priority: high
state_hub_task_id: "13cd3aec-c87d-5d3f-a421-39d8ff131edd"
```
### T02 — Add the NetKingdom authentication source
- an ExternalSecret delivering the `forgejo` client secret from OpenBao to a
Secret in the `forgejo` namespace. Custody path is
`platform/workloads/keycape/forgejo`, field `CLIENT_SECRET`, read by ESO through
Kubernetes-auth role `external-secrets-keycape-forgejo-forgejo`, which carries
only policy `workload-kv-read-keycape-forgejo-forgejo` (net-kingdom 074b3a0;
replaces the earlier `platform/workloads/forgejo/netkingdom-oidc-client` proposal). The
SA/SecretStore/ExternalSecret shape follows the NK-WP-0048
`deliver-consumer-secret` receipt contract
(`docs/evidence/nk48-t16-owner-review/owner-review-railiance-apps.json`)
- `gitea.oauth`: name `netkingdom` (must match the redirect URI registered in
key-cape), provider `openidConnect`, auto-discovery from
`https://kc.coulomb.social/.well-known/openid-configuration`, scopes
`openid profile email groups`, group-claim name `groups`
- `oauth2_client` settings: no automatic account creation for unknown subjects;
account linking to existing local accounts by username after a successful
local sign-in (so the founder and agent accounts keep their history)
- Helm upgrade with the previous revision noted for rollback
Local password sign-in stays enabled.
Acceptance: the "Sign in with netkingdom" option appears. Local sign-in still
works. Rollback is one `helm rollback` to the noted revision.
```task
id: RAPPS-WP-0016-T03
status: wait
depends_on: [RAPPS-WP-0016-T02]
blocking_reason: "Linking and team mapping follow a working authentication source."
priority: high
state_hub_task_id: "81f072aa-c316-511e-a2cd-21dd1b1d0a00"
```
### T03 — Link accounts and map groups to teams
- The founder links their account through NetKingdom (MFA), then signs in again
through NetKingdom only and sees the same repositories, organisations and
admin rights.
- Map NetKingdom groups (names agreed in KEY-WP-0038-T01) to organisation teams:
owners and readers at least. Create the read-only teams that
ORGREF-WP-0002-T06 consumers will use.
- Apply KEY-WP-0038-T03's decision on agents and services: NetKingdom sign-in, or
scoped tokens bound to service identities.
Acceptance: founder and one agent work through NetKingdom; group-to-team mapping
verified by adding and removing one test membership; break-glass still works.
```task
id: RAPPS-WP-0016-T04
status: wait
depends_on: [RAPPS-WP-0016-T03]
needs_human: true
blocking_reason: "Restricting local password sign-in is a founder decision once NetKingdom sign-in is proven."
priority: medium
state_hub_task_id: "32c54737-c40f-5fde-9b91-163f8dcb0068"
```
### T04 — Decide on local password sign-in
Once NetKingdom sign-in has been used for a while without problems, the founder
decides whether local password sign-in is turned off for everyone except
break-glass. This is not required to close the forge; it is the next tightening
step, taken separately.
```task
id: RAPPS-WP-0016-T05
status: wait
depends_on: [RAPPS-WP-0016-T02]
blocking_reason: "Waits for net-kingdom's answer to the Apps 1.3 needs-change record (the-custodian docs/changes/netkingdom-target-2026-10-17/nk48-1.3-owner-review/owner-review-railiance-apps.json: RAPPS-1.3-C1..C3) and the re-frozen 1.3 candidate."
priority: medium
state_hub_task_id: "728786c9-f1f9-5983-a6a4-dea21faf67f5"
```
### T05 — Apps owner seams for NK-WP-0048 consumer steps
Implement the real Apps capabilities behind the `deliver-consumer-secret` and
`hand-over` adapters, as owner-run paths (option C): `owner_apply` /
`owner_remove` emitting `netkingdom.consumer-secret-delivery.v1` receipts from the
T02 objects; a consumer verifier that observes Forgejo sign-in and the T03
positive/negative group probes; and a committed-evidence hand-over receipt store.
See the owner-review record for the contract.
Acceptance: receipts produced from the live T02/T03 run validate against the
adapters' checks with no value-bearing keys.
## Also in scope: stale node credential
The k3s `registries.yaml` on railiance01 still holds a login for the frozen Gitea
host `92.205.130.254` (ORGREF-WP-0002-T02). Coordinate its removal with the node
owner when ORGREF-WP-0002-T06 adds the forge registry login, in the same change.
## T06 — Package the reviewed consumer source through the Apps build path
```task
id: RAPPS-WP-0016-T06
status: done
priority: high
```
Completed 2026-10-18, source build tooling only. The existing Apps Makefile now
has explicit prepare, public-dependency acquisition, offline build, artifact
verification and local OCI export targets for the pinned official Forgejo11.0.3
source plus reviewed multi-value claim patch. Source/toolchains/locks/compiler
inputs/base image are fixed. Third-party application source stays in a new /tmp
workspace; Apps holds the release input lock, patch and build recipe.
The original build profile produced identical frontend assets, bindata sources
and complete static executable in two workspaces, and identical local OCI
archives in two no-cache exports. Independent review then found host process
argv visibility through /proc (APPSBUILD-R1-F01). The revised recipe adds a
private PID namespace; exact source and synthetic canary regression are separately
reviewed. The original full builds are historical r1-profile evidence; no full
r2 build is claimed. Original packet/review and failure history remain in
Custodian apps-forgejo-release-build-r1 and apps-release-independent-review-r1;
the correction is apps-forgejo-release-build-r2. This is coordinator source
integration after independent technical review, not formal owner assent or image
admission. Helm values, deployed image, local sign-in and visibility are unchanged.
NK-WP-0048-T39 remains progress for the full release acceptance scope.
## T07 — Keep the client secret out of process arguments
```task
id: RAPPS-WP-0016-T07
status: progress
priority: high
```
Implement and independently review a real Forgejo add/update --secret-file path
and the actual chart helper/mount adaptation. Preserve the existing CLIENT_SECRET
key and custody route; use no agent-value argument or environment fallback. Test
bounded stable nofollow file reads, exact existing minted-secret encoding,
mutual exclusion/update preservation, fixed errors and actual Helm rendering.
Private mount identity/reader set and new package/type revisions need explicit
owner/runtime admission. The in-progress isolated candidate is Custodian
forgejo-private-input-r1; source completion is distinct from T02 native delivery.
## T08 — Provide a transactional application-source inverse and durable recovery
```task
id: RAPPS-WP-0016-T08
status: progress
priority: high
```
Implement actual owner database primitives that record operation intent/outcome
in the same durable database, compare complete raw persisted before/post/current
source state privately, and serialize conflicting application writers at the DB
boundary. Never emit stored credential/config bytes or delete/detach linked users
or a preexisting/shared source. SQLite and PostgreSQL transaction semantics must
be tested against the real app packages; unsupported backends refuse.
T05 and NK-WP-0048-T34 additionally require actual authenticated execution and
fresh inverse sessions, admitted evidence/recovery and exclusion of every release
writer, including Helm/runtime writers. The candidate DB primitive alone does
not establish those facilities. Helm rollback/omission does not remove persisted
OAuth sources: verify the exact app-state inverse before any image downgrade.
If links prevent removal, retain the extended image and reconcile. The earlier
T02 single-Helm-rollback statement is not sufficient recovery for this extension;
its historical text is retained and corrected here.
## T09 — Enforce authenticated Access Engine decisions in the application path
```task
id: RAPPS-WP-0016-T09
status: todo
priority: high
```
Use the producer-owned decision format/canonical bytes and independently admitted
signer/policy/request pins. Forgejo must verify the caller's issuer/tenant and
assurance facts, obtain and authenticate the exact Access Engine resource/action
decision, and refuse missing, stale, wrong-pin, unavailable or malformed replies.
Keep the original three-group any-of access set as policy input; its local
compatibility gate is not a substitute PDP or an architecture exception. An
issuer allowed/denied claim cannot manufacture authorization. Source integration
needs real provider/callback/session wiring and meaningful producer-consumer
positive/adverse tests before re-freezing the case and package. Existing break-
glass/local account and linking behavior remain within the declared owner scope.