Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,19 +488,18 @@ issue-type change before the first mutation.
## Metaserver development credentials

The `development` environment of `atrinik/metaserver-worker` (repository ID
1324297032) holds the three value-free lifecycle entries consumed only by
1324297032) holds the two value-free lifecycle entries consumed only by
`.github/workflows/deploy-development.yml`. Zoey Seraphina Rose, an Atrinik
organization owner, is accountable for verification and rotation.

`CLOUDFLARE_API_TOKEN` is account-owned with intended Workers Scripts Edit and
D1 Read permissions. Its account-wide edit authority can also edit PROD; the
workflow's exact DEV configuration and resource fences provide the target
boundary. `ATRINIK_DELIVERY_RESOURCE_READ_TOKEN` is account-owned with intended
Workers Scripts Read. `ATRINIK_PRODUCTION_BUILDS_READ_TOKEN` is user-scoped
with intended Workers CI Read and Workers Scripts Read for the retained-writer
fence. Do not describe any of these credentials as restricted to one Worker.
Workers Scripts Read. Do not describe either credential as restricted to one
Worker.

All three environment names were installed and verified on 2026-10-11; bounded
Both retained credential names were installed and verified on 2026-10-11; bounded
runtime GET checks passed. Effective provider permission metadata is unreadable,
and the deployment token's write permission has not yet been proven by its
owning workflow. Name metadata does not verify values, scope or expiry.
Expand Down Expand Up @@ -1190,7 +1189,7 @@ The names-only `production` environment inventory declares the reviewed
production-promotion contract: protected branches enabled,
custom policies disabled, no custom patterns and no required reviewers. Solo
owner dispatch of the exact reviewed inputs remains the approval boundary.
The eight secret names and two variable names are desired state, not proof that
The seven secret names and one variable name are desired state, not proof that
the environment or effective credentials exist. The recovery public-key input
remains pending the owning workflow merge; provision it only after that reviewed
consumer is merged. Provision through supported
Expand Down Expand Up @@ -1246,9 +1245,9 @@ database identity. Required `Workers Scripts Edit` and `D1 Read` permissions
remain the intended deployment contract; provider permission metadata and
write capability are unproven. Provider creation and expiry remain unknown.
Its 2027-01-10 rotation deadline is internal 90-day policy, not provider expiry.
The two owner-authorized shared read-only control-plane credentials retain their
2026-10-11 qualification and 2027-01-09 internal deadlines; expiry remains unknown.
Their separate production lifecycle entries declare desired placement, not
The owner-authorized shared `ATRINIK_DELIVERY_RESOURCE_READ_TOKEN` retains its
2026-10-11 qualification and 2027-01-09 internal deadline; expiry remains unknown.
Its separate production lifecycle entry declares desired placement, not
installation or successful use by the production workflow. Provision and verify
only after this inventory is reviewed and accepted.

Expand Down Expand Up @@ -1487,14 +1486,19 @@ environment. The environment permits only the exact `main` branch and has no
required reviewers, secrets, or variables. The desired Pages build type is
`workflow`; the consuming workflow is
`.github/workflows/daily-client-performance.yml`, bound by the immutable
`actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e` marker.
`actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346` marker.

The live legacy `main`-root source is a bounded pre-activation state only while
A legacy `main`-root source is a bounded pre-activation state only while
that marker is absent from the default-branch workflow.
`bin/verify-manual-settings` reports it as `PENDING`. Once the reviewed Classic
workflow is merged, the same verifier requires the Actions source and fails on
any lingering legacy source. It never changes the source itself.

Classic PR #547 merged the v5.0.1 deployment action update on 2026-10-03.
The inventory marker follows that reviewed immutable action. Read-only metadata
on 2026-10-31 showed the site already uses the Actions source; this verifies
configuration, not successful execution of the latest Pages deployment.

Before activation, verify the repository, current Pages site, environment, and
the merged workflow without changing live state:

Expand All @@ -1513,7 +1517,7 @@ gh api repos/atrinik/classic/environments/github-pages/variables \
--jq '{total_count,names:[.variables[].name]}'
gh api 'repos/atrinik/classic/contents/.github/workflows/daily-client-performance.yml?ref=main' \
--jq -r .content | base64 --decode | \
grep -F 'actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e'
grep -F 'actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346'
```

Require the stable repository identity and `main` default branch, exact site
Expand Down
3 changes: 0 additions & 3 deletions bin/validate
Original file line number Diff line number Diff line change
Expand Up @@ -828,9 +828,6 @@ jq -e \
elif .secret_name == "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN" then
.credential_type == "cloudflare_account_token" and
.required_scopes == ["Workers Scripts Read"]
elif .secret_name == "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN" then
.credential_type == "cloudflare_user_token" and
.required_scopes == ["Workers CI Read", "Workers Scripts Read"]
else false end)
end)
) and
Expand Down
55 changes: 3 additions & 52 deletions config/manual-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,10 @@
"ATRINIK_DEVELOPMENT_CORE_CONFIG",
"ATRINIK_DEVELOPMENT_PUBLISHER_CONFIG",
"ATRINIK_DEVELOPMENT_RENDEZVOUS_CONFIG",
"ATRINIK_PRODUCTION_BUILDS_READ_TOKEN",
"CLOUDFLARE_ACCOUNT_ID",
"CLOUDFLARE_API_TOKEN"
],
"variable_names": [
"ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"
]
"variable_names": []
},
{
"deployment_branch_policy": {
Expand All @@ -334,22 +331,20 @@
"secret_names": [
"ATRINIK_DELIVERY_RESOURCE_POLICY",
"ATRINIK_DELIVERY_RESOURCE_READ_TOKEN",
"ATRINIK_PRODUCTION_BUILDS_READ_TOKEN",
"ATRINIK_PRODUCTION_CORE_CONFIG",
"ATRINIK_PRODUCTION_PUBLISHER_CONFIG",
"ATRINIK_PRODUCTION_RENDEZVOUS_CONFIG",
"CLOUDFLARE_ACCOUNT_ID",
"CLOUDFLARE_API_TOKEN"
],
"variable_names": [
"ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY",
"ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"
"ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY"
]
}
],
"github_pages_sites": [
{
"activation_marker": "actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e",
"activation_marker": "actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346",
"build_type": "workflow",
"environment": "github-pages",
"https_enforced": true,
Expand Down Expand Up @@ -459,28 +454,6 @@
"secret_name": "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN",
"secret_scope": "environment"
},
{
"credential_type": "cloudflare_user_token",
"consumers": [
".github/workflows/deploy-development.yml"
],
"environment": "development",
"last_verified_on": "2026-10-11",
"owner": "Zoey Seraphina Rose (Atrinik organization owner)",
"purpose": "Read retained Builds and Worker settings to prove the stopped-writer fence without deployment.",
"repository": "atrinik/metaserver-worker",
"repository_id": 1324297032,
"required_scopes": [
"Workers CI Read",
"Workers Scripts Read"
],
"rotate_by": "2027-01-09",
"rotation_cadence_days": 90,
"rotation_owner": "Zoey Seraphina Rose (Atrinik organization owner)",
"runbook": "README.md#metaserver-development-credentials",
"secret_name": "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN",
"secret_scope": "environment"
},
{
"consumers": [
".github/workflows/promote-production.yml"
Expand Down Expand Up @@ -523,28 +496,6 @@
"runbook": "README.md#metaserver-production-credentials",
"secret_name": "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN",
"secret_scope": "environment"
},
{
"consumers": [
".github/workflows/promote-production.yml"
],
"credential_type": "cloudflare_user_token",
"environment": "production",
"last_verified_on": "2026-10-11",
"owner": "Zoey Seraphina Rose (Atrinik organization owner)",
"purpose": "Read retained Builds and Worker settings to prove the stopped-writer fence without deployment. Reuse in the production control-plane workflow is owner-authorized; this record declares production placement, which remains pending. Provider expiry is unknown and rotate_by is internal policy.",
"repository": "atrinik/metaserver-worker",
"repository_id": 1324297032,
"required_scopes": [
"Workers CI Read",
"Workers Scripts Read"
],
"rotate_by": "2027-01-09",
"rotation_cadence_days": 90,
"rotation_owner": "Zoey Seraphina Rose (Atrinik organization owner)",
"runbook": "README.md#metaserver-production-credentials",
"secret_name": "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN",
"secret_scope": "environment"
}
],
"github_packages_actions_access": [
Expand Down
13 changes: 7 additions & 6 deletions tests/validate-manual-credentials.sh
Original file line number Diff line number Diff line change
Expand Up @@ -198,21 +198,21 @@ jq -e '

jq -e '
[.github_actions_credentials[] | select(.environment == "development")] as $credentials |
($credentials | length) == 3 and
($credentials | length) == 2 and
all($credentials[];
.repository == "atrinik/metaserver-worker" and .repository_id == 1324297032 and
.environment == "development" and .consumers == [".github/workflows/deploy-development.yml"] and
.last_verified_on == "2026-10-11" and .rotate_by == "2027-01-09" and
.rotation_cadence_days == 90 and .owner == "Zoey Seraphina Rose (Atrinik organization owner)"
) and
([$credentials[].secret_name] | sort) == [
"ATRINIK_DELIVERY_RESOURCE_READ_TOKEN", "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN", "CLOUDFLARE_API_TOKEN"
"ATRINIK_DELIVERY_RESOURCE_READ_TOKEN", "CLOUDFLARE_API_TOKEN"
]
' "${root}/config/manual-settings.json" >/dev/null

jq -e '
[.github_actions_credentials[] | select(.environment == "production")] as $credentials |
($credentials | length) == 3 and
($credentials | length) == 2 and
all($credentials[];
.repository == "atrinik/metaserver-worker" and .repository_id == 1324297032 and
.consumers == [".github/workflows/promote-production.yml"] and
Expand All @@ -223,7 +223,7 @@ jq -e '
else .last_verified_on == "2026-10-11" and .rotate_by == "2027-01-09" end)
) and
([$credentials[].secret_name] | sort) == [
"ATRINIK_DELIVERY_RESOURCE_READ_TOKEN", "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN", "CLOUDFLARE_API_TOKEN"
"ATRINIK_DELIVERY_RESOURCE_READ_TOKEN", "CLOUDFLARE_API_TOKEN"
]
' "${root}/config/manual-settings.json" >/dev/null

Expand All @@ -244,7 +244,8 @@ for invalid in \
'.github_actions_credentials[-1].consumers = [".github/workflows/deploy-development.yml"]' \
'.github_actions_credentials[-1].runbook = "README.md#metaserver-development-credentials"' \
'.github_actions_credentials[-1].required_scopes += ["Workers Scripts Edit"]' \
'.github_actions_credentials[-1].credential_type = "cloudflare_account_token"'; do
'.github_actions_credentials[-1].credential_type = "cloudflare_user_token"' \
'.github_actions_credentials[-1] |= (.secret_name = "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN" | .credential_type = "cloudflare_user_token" | .required_scopes = ["Workers CI Read", "Workers Scripts Read"])'; do
jq "$invalid" "${temporary}/production-credentials.json" >"${temporary}/config/manual-settings.json"
if ATRINIK_VALIDATION_TODAY=2026-10-18 "${temporary}/bin/validate" >/dev/null 2>&1; then
echo "error: validator accepted malformed PROD credential lifecycle: ${invalid}" >&2
Expand All @@ -255,7 +256,7 @@ done
for invalid in \
'.github_actions_credentials[1].required_scopes = ["Workers Scripts Read"]' \
'.github_actions_credentials[2].credential_type = "cloudflare_user_token"' \
'.github_actions_credentials[3].environment = "production"' \
'(.github_actions_credentials[] | select(.environment == "development" and .secret_name == "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN")).environment = "production"' \
'.github_actions_credentials[1].repository_id = 1' \
'.github_actions_credentials[1].consumers = [".github/workflows/publish.yml"]' \
'.github_actions_credentials[1].credential_value = "secret"'; do
Expand Down
9 changes: 4 additions & 5 deletions tests/validate-manual-environments.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,10 @@ jq -e '
"ATRINIK_DEVELOPMENT_CORE_CONFIG",
"ATRINIK_DEVELOPMENT_PUBLISHER_CONFIG",
"ATRINIK_DEVELOPMENT_RENDEZVOUS_CONFIG",
"ATRINIK_PRODUCTION_BUILDS_READ_TOKEN",
"CLOUDFLARE_ACCOUNT_ID",
"CLOUDFLARE_API_TOKEN"
],
variable_names: ["ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"]
variable_names: []
}) and
any(.github_actions_environments[]; . == {
deployment_branch_policy: {custom_branch_policies: false, patterns: [], protected_branches: true},
Expand All @@ -117,14 +116,14 @@ jq -e '
required_reviewers: [],
secret_names: [
"ATRINIK_DELIVERY_RESOURCE_POLICY", "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN",
"ATRINIK_PRODUCTION_BUILDS_READ_TOKEN", "ATRINIK_PRODUCTION_CORE_CONFIG",
"ATRINIK_PRODUCTION_CORE_CONFIG",
"ATRINIK_PRODUCTION_PUBLISHER_CONFIG", "ATRINIK_PRODUCTION_RENDEZVOUS_CONFIG",
"CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"
],
variable_names: ["ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY", "ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"]
variable_names: ["ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY"]
}) and
.github_pages_sites == [{
activation_marker: "actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e",
activation_marker: "actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346",
build_type: "workflow",
environment: "github-pages",
https_enforced: true,
Expand Down
16 changes: 7 additions & 9 deletions tests/verify-manual-settings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ repos/atrinik/classic/pages)
workflow='name: Daily Classic client performance'
if [[ ${FAKE_GH_SCENARIO} == pages-active ||
${FAKE_GH_SCENARIO} == pages-activation-missing ]]; then
workflow='uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e'
workflow='uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346'
fi
if [[ ${FAKE_GH_SCENARIO} == pages-workflow-metadata-drift ]]; then
jq -n '{type: "dir", encoding: "none", content: null}'
Expand Down Expand Up @@ -619,17 +619,16 @@ repos/atrinik/metaserver-worker/environments/production)
exit 79
;;
"repos/atrinik/metaserver-worker/environments/production/secrets?per_page=100&page=1")
jq -n '{total_count: 8, secrets: [
jq -n '{total_count: 7, secrets: [
{name: "ATRINIK_DELIVERY_RESOURCE_POLICY"}, {name: "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN"},
{name: "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN"}, {name: "ATRINIK_PRODUCTION_CORE_CONFIG"},
{name: "ATRINIK_PRODUCTION_CORE_CONFIG"},
{name: "ATRINIK_PRODUCTION_PUBLISHER_CONFIG"}, {name: "ATRINIK_PRODUCTION_RENDEZVOUS_CONFIG"},
{name: "CLOUDFLARE_ACCOUNT_ID"}, {name: "CLOUDFLARE_API_TOKEN"}
]}'
;;
"repos/atrinik/metaserver-worker/environments/production/variables?per_page=100&page=1")
jq -n '{total_count: 2, variables: [
{name: "ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY"},
{name: "ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"}
jq -n '{total_count: 1, variables: [
{name: "ATRINIK_PRODUCTION_RECOVERY_PUBLIC_KEY"}
]}'
;;
repos/atrinik/metaserver-worker/environments/development)
Expand All @@ -652,19 +651,18 @@ repos/atrinik/metaserver-worker/environments/development)
jq -n '{total_count: 0, secrets: []}'
exit 0
fi
jq -n '{total_count: 8, secrets: [
jq -n '{total_count: 7, secrets: [
{name: "ATRINIK_DELIVERY_RESOURCE_POLICY"},
{name: "ATRINIK_DELIVERY_RESOURCE_READ_TOKEN"},
{name: "ATRINIK_DEVELOPMENT_CORE_CONFIG"},
{name: "ATRINIK_DEVELOPMENT_PUBLISHER_CONFIG"},
{name: "ATRINIK_DEVELOPMENT_RENDEZVOUS_CONFIG"},
{name: "ATRINIK_PRODUCTION_BUILDS_READ_TOKEN"},
{name: "CLOUDFLARE_ACCOUNT_ID"},
{name: "CLOUDFLARE_API_TOKEN"}
] | map(. + {updated_at: "2026-10-11T00:00:00Z"})}'
;;
"repos/atrinik/metaserver-worker/environments/development/variables?per_page=100&page=1")
jq -n '{total_count: 1, variables: [{name: "ATRINIK_PRODUCTION_WRITER_FENCE_POLICY"}]}'
jq -n '{total_count: 0, variables: []}'
;;
repos/atrinik/classic/environments/discord-release)
if [[ ${FAKE_GH_SCENARIO} == missing-environment ]]; then
Expand Down
Loading