docs: cohort-1 runbook: tmpfs fence staging, --source - follow-up, v0.28.0
Per platform-1e's ruling on the 7a gap: - 7a.2 keeps main's fence-credentials --source file, staged on tmpfs at /run/carlos-fence-stage/ (directory made by root with umask 077), written with install -m 0600 -o root -g root /dev/stdin straight from get-parameter --with-decryption, removed by a trap in the same subshell on success or failure, and confirmed gone with stat. - --source - recorded as a follow-up for production cohorts, beside the independent writer and key rotation; the open question is removed. - 7a.1 names the operator principal (user/remote-agent, profile kass) and that platform-1e states it when taking 7a.1 to Paul. - Step 1 names v0.28.0, cut from main 26065378; dev rolls first and the trial waits until dev is rolled and checked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+50
−27
docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md+50 −27
CI passed — run details
CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok amadan.net/carlos/platform.git/launchctx 0.011s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok github.com/carlosframework/platform 310.870s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 2.792s
ok github.com/carlosframework/platform/cmd/moveprobe 92.222s
ok github.com/carlosframework/platform/cmd/zddprobe 0.710s
ok github.com/carlosframework/platform/internal/activator 251.658s
ok github.com/carlosframework/platform/internal/agentsock 0.027s
ok github.com/carlosframework/platform/internal/alerting 0.008s
ok github.com/carlosframework/platform/internal/analytics 0.021s
ok github.com/carlosframework/platform/internal/appconfig 2.447s
ok github.com/carlosframework/platform/internal/apperr 0.086s
ok github.com/carlosframework/platform/internal/applog 0.141s
ok github.com/carlosframework/platform/internal/awsinv 0.005s
ok github.com/carlosframework/platform/internal/boxchoice 0.009s
ok github.com/carlosframework/platform/internal/boxid 0.864s
? github.com/carlosframework/platform/internal/boxid/boxidtest [no test files]
? github.com/carlosframework/platform/internal/boxid/internal/signtest [no test files]
ok github.com/carlosframework/platform/internal/boxvolumes 0.015s
ok github.com/carlosframework/platform/internal/caps 0.017s
ok github.com/carlosframework/platform/internal/certwarm 0.010s
ok github.com/carlosframework/platform/internal/cgroup 0.698s
ok github.com/carlosframework/platform/internal/changelog 0.308s
ok github.com/carlosframework/platform/internal/claimactivation 0.033s
ok github.com/carlosframework/platform/internal/clamd 0.061s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 407.475s
? github.com/carlosframework/platform/internal/controlname [no test files]
? github.com/carlosframework/platform/internal/controlsock [no test files]
ok github.com/carlosframework/platform/internal/dbdoor 6.492s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.009s
ok github.com/carlosframework/platform/internal/dbverify 0.007s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.004s
ok github.com/carlosframework/platform/internal/domains 2.400s
ok github.com/carlosframework/platform/internal/doorkey 0.006s
ok github.com/carlosframework/platform/internal/economics 0.004s
ok github.com/carlosframework/platform/internal/edge 44.885s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.009s
ok github.com/carlosframework/platform/internal/fleetapi 0.136s
ok github.com/carlosframework/platform/internal/gate 1.656s
ok github.com/carlosframework/platform/internal/genselect 0.015s
ok github.com/carlosframework/platform/internal/geo 0.018s
ok github.com/carlosframework/platform/internal/geoip 0.030s
ok github.com/carlosframework/platform/internal/historyreadback 0.177s
ok github.com/carlosframework/platform/internal/host 173.851s
ok github.com/carlosframework/platform/internal/hostactors 0.622s
ok github.com/carlosframework/platform/internal/hostbox 2.662s
ok github.com/carlosframework/platform/internal/hostclaim 0.563s
ok github.com/carlosframework/platform/internal/hostevidence 0.013s
ok github.com/carlosframework/platform/internal/hostexec 4.940s
ok github.com/carlosframework/platform/internal/hostfence 0.033s
ok github.com/carlosframework/platform/internal/hostfiles 10.493s
ok github.com/carlosframework/platform/internal/hostfloor 0.016s
ok github.com/carlosframework/platform/internal/hostguard 1.039s
ok github.com/carlosframework/platform/internal/hostops 1.593s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.016s
ok github.com/carlosframework/platform/internal/hostquarantine 0.016s
ok github.com/carlosframework/platform/internal/hostrelocate 0.462s
ok github.com/carlosframework/platform/internal/hostresolve 0.152s
ok github.com/carlosframework/platform/internal/hostwrite 0.016s
ok github.com/carlosframework/platform/internal/infraview 0.016s
ok github.com/carlosframework/platform/internal/instancectl 5.228s
ok github.com/carlosframework/platform/internal/instanceexec 2.727s
ok github.com/carlosframework/platform/internal/instancefs 0.019s
ok github.com/carlosframework/platform/internal/instancekey 0.016s
ok github.com/carlosframework/platform/internal/instanceupdates 0.020s
ok github.com/carlosframework/platform/internal/layout 1.522s
ok github.com/carlosframework/platform/internal/lbhealth 0.017s
ok github.com/carlosframework/platform/internal/lease 9.833s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.018s
ok github.com/carlosframework/platform/internal/ledger 0.017s
ok github.com/carlosframework/platform/internal/mail 0.168s
ok github.com/carlosframework/platform/internal/maintenance 0.085s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.542s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.088s
ok github.com/carlosframework/platform/internal/metrics 0.005s
ok github.com/carlosframework/platform/internal/moves 21.069s
ok github.com/carlosframework/platform/internal/moves/archive 0.776s
ok github.com/carlosframework/platform/internal/objstore 0.193s
ok github.com/carlosframework/platform/internal/ops 0.192s
ok github.com/carlosframework/platform/internal/park 0.220s
ok github.com/carlosframework/platform/internal/privatefile 0.004s
ok github.com/carlosframework/platform/internal/provision 35.331s
ok github.com/carlosframework/platform/internal/publicrelease 0.006s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.494s
ok github.com/carlosframework/platform/internal/relay 7.258s
ok github.com/carlosframework/platform/internal/release 21.664s
ok github.com/carlosframework/platform/internal/rollout 3.740s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.008s
ok github.com/carlosframework/platform/internal/rootparticipation 0.058s
ok github.com/carlosframework/platform/internal/rootstate 0.027s
ok github.com/carlosframework/platform/internal/runs 0.583s
ok github.com/carlosframework/platform/internal/s3compat 0.006s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.516s
ok github.com/carlosframework/platform/internal/seeds 0.011s
ok github.com/carlosframework/platform/internal/sim/hostlife 9.415s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 3.532s
ok github.com/carlosframework/platform/internal/status 0.042s
ok github.com/carlosframework/platform/internal/steering 0.006s
ok github.com/carlosframework/platform/internal/stopevidence 0.291s
ok github.com/carlosframework/platform/internal/svcrole 0.004s
ok github.com/carlosframework/platform/internal/telemetry 0.004s
ok github.com/carlosframework/platform/internal/termfence 0.004s
ok github.com/carlosframework/platform/internal/tunnelclient 0.004s
ok github.com/carlosframework/platform/internal/unixdial 0.002s
ok github.com/carlosframework/platform/internal/updatewords 0.004s
ok github.com/carlosframework/platform/internal/usage 0.004s
ok github.com/carlosframework/platform/internal/version 0.001s
ok github.com/carlosframework/platform/internal/vet 1.578s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 48824482 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
minio: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
minio: downloaded, digest verified
mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
mc: downloaded, digest verified
minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
buckets and scoped user ready
=== RUN TestDeliveredContractMinio
=== RUN TestDeliveredContractMinio/put
=== RUN TestDeliveredContractMinio/get_round-trips_the_body
=== RUN TestDeliveredContractMinio/list_shows_the_key
=== RUN TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN TestDeliveredContractMinio/delete_removes_it
=== RUN TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
--- PASS: TestDeliveredContractMinio/put (0.00s)
--- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
--- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
--- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
--- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok github.com/carlosframework/platform/internal/objstore 0.031s
=== RUN TestT4StorageProbeMinio
2026/10/17 20:46:43 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DF6C12822B921A, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok github.com/carlosframework/platform/internal/host 0.023s
minio contract: PASS
diff --git a/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md b/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md| index b01d169d7..7a2f59066 100644 |
| --- a/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md |
| +++ b/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md |
| @@ -191,7 +191,7 @@ Pass: all twelve are root-owned regular files in `/etc/systemd/system`; the edge |
| ## Blockers |
| -1. **Release.** No release contains 26065378 (Plan 14 Parts 2 and 3, the activation tools) or e8e961dd (the empty-app writer fix). Step 1. |
| +1. **Release.** No published release yet contains 26065378 (Plan 14 Parts 2 and 3, the activation tools) or e8e961dd (the empty-app writer fix). v0.28.0 is being cut from 26065378. Step 1. |
| 2. **Empty app segment.** 267 objects under `apps/bab//` (P5). Source: leo's app-less `proof*` routes, removed (2026-10-16). Cleanup waits for the e8e961dd release to reach leo and for Paul's approval. Step 2. |
| 3. **IAM.** Leo's role lacks the version actions, and dev has neither the deployment bucket policy nor a fence-writer role (P2). Step 3. |
| @@ -199,20 +199,21 @@ Pass: all twelve are root-owned regular files in `/etc/systemd/system`; the edge |
| Paul deferred these for this trial only. They are not blockers here, and they must be closed before any non-trial cohort: |
| - **Plan 15's independent claim writer.** Leo's instance role can write `control/hosts/`, so the box's own credentials could rewrite its claims. |
| +- **`fence-credentials --source -`.** For the trial, the credentials pass through a tmpfs staging file under `/run` (step 7a.2). Reading standard input instead is a follow-up for production cohorts (platform-1e is filing it on amadan). |
| - **Key rotation.** The release signing key is not rotated for the trial, and no rotation schedule is set for the fence-writer bootstrap keys. (The separate exposure, box roles reading `/carlos/release-key`, is resolved; see P2.) |
| ## Step 1. Release and roll, claims off |
| -What: cut a release from main containing 26065378 and e8e961dd, and roll it with every claim switch unset. Dev goes first. Flagship does not need this release before dev's window (Paul, 2026-10-16); its roll is separate. |
| +What: v0.28.0, cut from main at 26065378 (it contains Plan 14 Parts 2 and 3, the activation tools and e8e961dd), rolled with every claim switch unset. Dev rolls first. The trial waits until dev is rolled and checked. Flagship does not need this release before dev's window (Paul, 2026-10-16); its roll is separate. |
| Paul's go: to cut the release, then to roll dev. |
| -1. Cut the release by the README section "Releasing the platform". Check `gh release list -R carlosframework/releases` and `git ls-remote --tags origin` before choosing the number. |
| +1. Cut v0.28.0 from 26065378 by the README section "Releasing the platform" (in progress on 2026-10-17). Confirm with `gh release list -R carlosframework/releases` that v0.28.0 is published before rolling. |
| 2. Roll the dev boxes on the new road only: |
| ```bash |
| - carlos system update --console https://platform.dev.carlosframework.com --channel stable --version vX.Y.Z --yes |
| - carlos system update --console https://platform.dev.carlosframework.com --channel canary --version vX.Y.Z --yes |
| + carlos system update --console https://platform.dev.carlosframework.com --channel stable --version v0.28.0 --yes |
| + carlos system update --console https://platform.dev.carlosframework.com --channel canary --version v0.28.0 --yes |
| carlos system status --console https://platform.dev.carlosframework.com |
| ``` |
| @@ -221,9 +222,9 @@ Paul's go: to cut the release, then to roll dev. |
| 4. Check dev end to end: wake `wakecheck` on sophie through DNS (claims are still off, and wakecheck is still on both boxes). |
| Expected: |
| -- `system status` shows all three dev boxes `current` at vX.Y.Z; |
| +- `system status` shows all three dev boxes `current` at v0.28.0; |
| - `curl -sI https://platform.dev.carlosframework.com/ | grep -i x-carlos-version` shows the release commit; |
| -- on leo, `systemctl show carlos-instance-control.service -p ActiveEnterTimestamp` is later than the update, and `/opt/carlos/carlos version` prints vX.Y.Z; |
| +- on leo, `systemctl show carlos-instance-control.service -p ActiveEnterTimestamp` is later than the update, and `/opt/carlos/carlos version` prints v0.28.0; |
| - `/opt/carlos/carlos system claims help` on leo prints main's usage, listing `inspect`, `run`, `evidence-key`, `fence-credentials`, `console-config`, `console-report` and `install-control`; |
| - the wake answers 200. |
| @@ -602,7 +603,9 @@ Residual exposure: between 7a.2's write and its delete, leo's role can read the |
| Paul's go: separate gate, for creating the key, its policy and leo's temporary read grant. |
| -Dev's infrastructure is OpenTofu in `platform-infrastructure/dev`, so the key is declared there. Add this file on a reviewed branch (the operator ARN is the principal behind profile `kass` today, `arn:aws:iam::640012953448:user/remote-agent`; confirm it at approval, and it must also be the principal that runs `tofu apply`, or the key policy lockout check refuses the key): |
| +The operator principal in the key policy is `arn:aws:iam::640012953448:user/remote-agent`, the user behind profile `kass`. platform-1e will state this when taking 7a.1 to Paul. It must also be the principal that runs `tofu apply`, or the key policy lockout check refuses the key. |
| + |
| +Dev's infrastructure is OpenTofu in `platform-infrastructure/dev`, so the key is declared there. Add this file on a reviewed branch: |
| ```hcl |
| # platform-infrastructure/dev/cohort1-fence-kms.tf |
| @@ -711,29 +714,50 @@ box_put "$LEO" fence-role-arn /root/claim-trial/fence-role-arn |
| Expected: version `1`, an 8-digit fingerprint to compare in part 2, and `staged` for the role ARN (an ARN, not a secret). |
| -**2. On leo, read it without echoing it, straight into a protected file, and install it.** Main's `carlos system claims fence-credentials` has no stdin option: `--source` must be a root-owned regular file with mode `0600` or `0400`. So the value goes from `aws ssm get-parameter` straight into such a file, never to the terminal, then `fence-credentials` installs it. The AWS CLI on leo (v2, `/usr/bin/aws`) uses leo's instance role; do not set a profile. In the attended root shell on leo: |
| +**2. On leo, read it without echoing it into a tmpfs staging file, and install it.** For this trial main's `carlos system claims fence-credentials --source FILE` stays as it is (platform-1e, 2026-10-17): `--source` must be a root-owned regular file with mode `0600` or `0400`, and there is no stdin option. The staging file is held to four rules: |
| +- **tmpfs only:** it lives under `/run/carlos-fence-stage/`, never on disk. Root creates the directory with umask 077. |
| +- **Never readable by others:** `install -m 0600 -o root -g root /dev/stdin` writes it straight from `aws ssm get-parameter --with-decryption`, so it never exists with wider modes, and the value never reaches the terminal. |
| +- **Always deleted:** a `trap` in the same shell removes it as soon as `fence-credentials` returns, on success or failure. |
| +- **Checked:** `stat` confirms it is gone before anything else happens. |
| + |
| +The AWS CLI on leo (v2, `/usr/bin/aws`) uses leo's instance role; do not set a profile. In the attended root shell on leo, run the block as one subshell, so the `trap` fires when it ends however it ends: |
| ```bash |
| -set -euo pipefail |
| -umask 077 |
| -cd /root/claim-trial |
| -test ! -e fence-credentials.json |
| -aws --region eu-west-1 ssm get-parameter --name /carlos-staging/fence/carlos-dev-ie-b --with-decryption \ |
| - --query Parameter.Value --output text > fence-credentials.json |
| -stat -c '%U %a %h %s' fence-credentials.json |
| -python3 -c 'import json,sys,hashlib;print(hashlib.sha256(json.dumps(json.load(open(sys.argv[1])),sort_keys=True).encode()).hexdigest()[:8])' fence-credentials.json |
| -FENCE_ROLE=$(cat fence-role-arn) |
| -/opt/carlos/carlos system claims fence-credentials --source /root/claim-trial/fence-credentials.json \ |
| - --bucket carlos-dev-640012953448 --aws-region eu-west-1 --role "$FENCE_ROLE" --dry-run |
| -/opt/carlos/carlos system claims fence-credentials --source /root/claim-trial/fence-credentials.json \ |
| - --bucket carlos-dev-640012953448 --aws-region eu-west-1 --role "$FENCE_ROLE" |
| -rm -- /root/claim-trial/fence-credentials.json |
| +( |
| + set -euo pipefail |
| + umask 077 |
| + STAGE=/run/carlos-fence-stage |
| + SRC="$STAGE/credentials.json" |
| + install -d -m 0700 -o root -g root "$STAGE" |
| + test ! -e "$SRC" |
| + trap 'rm -f -- "$SRC"' EXIT |
| + aws --region eu-west-1 ssm get-parameter --name /carlos-staging/fence/carlos-dev-ie-b --with-decryption \ |
| + --query Parameter.Value --output text | install -m 0600 -o root -g root /dev/stdin "$SRC" |
| + stat -c '%U %a %h %s' "$SRC" |
| + python3 -c 'import json,sys,hashlib;print(hashlib.sha256(json.dumps(json.load(open(sys.argv[1])),sort_keys=True).encode()).hexdigest()[:8])' "$SRC" |
| + FENCE_ROLE=$(cat /root/claim-trial/fence-role-arn) |
| + /opt/carlos/carlos system claims fence-credentials --source "$SRC" \ |
| + --bucket carlos-dev-640012953448 --aws-region eu-west-1 --role "$FENCE_ROLE" --dry-run |
| + /opt/carlos/carlos system claims fence-credentials --source "$SRC" \ |
| + --bucket carlos-dev-640012953448 --aws-region eu-west-1 --role "$FENCE_ROLE" |
| +) |
| +echo "subshell exit=$?" |
| +if stat -- /run/carlos-fence-stage/credentials.json >/dev/null 2>&1; then |
| + echo "STAGING FILE STILL PRESENT: rm -f -- /run/carlos-fence-stage/credentials.json, then stop" |
| +else |
| + echo "staging file gone" |
| +fi |
| +rmdir -- /run/carlos-fence-stage |
| stat -c '%U %a %h' /etc/carlos/fence-writer/credentials.json |
| ``` |
| -Expected: `root 600 1 <size>`; the same fingerprint as part 1; both `fence-credentials` runs print their JSON summary (`"target": "/etc/carlos/fence-writer/credentials.json"`, `"mode": "0600"`); the staging file is removed; the installed file is `root 600 1`. Nothing prints a credential value. If anything fails, remove the staging file anyway, then go on to parts 3 to 5 before investigating. |
| +Expected: |
| +- `root 600 1 <size>` for the staging file, and the same fingerprint as part 1; |
| +- both `fence-credentials` runs print their JSON summary (`"target": "/etc/carlos/fence-writer/credentials.json"`, `"mode": "0600"`); |
| +- `subshell exit=0`, then `staging file gone`; |
| +- the installed file `root 600 1`. |
| -Gap for platform-1e: because `fence-credentials` has no stdin source, the plaintext sits in a root-only staging file (`/root/claim-trial`, `0700`) for the seconds between the read and the install. A `--source -` that reads standard input would remove that file. |
| +Nothing prints a credential value. If anything fails, the `trap` has already removed the staging file: confirm `staging file gone`, then go on to parts 3 to 5 before investigating. |
| **3. Delete the parameter immediately.** On the trusted host: |
| @@ -1311,9 +1335,8 @@ Not part of this trial (Paul, 2026-10-16). dennis-stenciling is placement `uk`, |
| ## Open questions |
| -Answered: dev-uk is out of this trial; the console is enrolled by the activation tools; the independent writer and key rotation are accepted trial gaps; box roles no longer read `/carlos/release-key`; the home name is `ie`; the `proof*` routes are removed; step 4 is approved; flagship does not need the release before dev's window; the automated offline window is replaced by the manual one; `jq` runs only on the trusted host and nothing is installed on the boxes; `install-control` runs once, before `journal-migrate`; the usage and docs edits for the removed commands are confirmed by Paul and on main. Fence credentials go by option (a): a one-time SecureString outside `/carlos/`, under a dedicated KMS key only leo's role can use, deleted and revoked straight after (step 7a). |
| +Answered: dev-uk is out of this trial; the console is enrolled by the activation tools; the independent writer and key rotation are accepted trial gaps; box roles no longer read `/carlos/release-key`; the home name is `ie`; the `proof*` routes are removed; step 4 is approved; flagship does not need the release before dev's window; the automated offline window is replaced by the manual one; `jq` runs only on the trusted host and nothing is installed on the boxes; `install-control` runs once, before `journal-migrate`; the usage and docs edits for the removed commands are confirmed by Paul and on main. Fence credentials go by option (a): a one-time SecureString outside `/carlos/`, under a dedicated KMS key only leo's role can use, deleted and revoked straight after (step 7a); on leo it passes only through a tmpfs staging file under `/run`, deleted by a `trap`; `--source -` is a follow-up for production cohorts. |
| For platform-1e: |
| 1. Should `hostops.Apps` skip an empty app segment instead of refusing, so one stray object cannot stop activation on a whole deployment? |
| 2. For a later teardown out of hold: how do writes made under the claim reach the claims-off restore path? |
| -3. `carlos system claims fence-credentials` reads only a `--source` file. Should it also read standard input (`--source -`), so step 7a.2 needs no plaintext staging file on leo? |