Clarify production handoff is not deployed
This commit is contained in:
1 parent
3d267afaee
commit
96ed0949ca
5 files changed
+69
-6
No files matched your search
@@ -1,4 +1,4 @@
|
||||
name: Prepare production deploy handoff
|
||||
name: Production handoff status (not deployed)
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -7,7 +7,8 @@ on:
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
validate-handoff:
|
||||
deployment-status:
|
||||
name: NOT DEPLOYED - handoff status only
|
||||
if: >-
|
||||
gitea.event.workflow_run.conclusion == 'success' &&
|
||||
gitea.event.workflow_run.event == 'workflow_run' &&
|
||||
@@ -55,3 +56,9 @@ jobs:
|
||||
trap 'rm -f "$metadata"' EXIT
|
||||
gitea-api GET "/repos/admin/akyldash/actions/runs/${SOURCE_RUN_ID}/artifacts" > "$metadata"
|
||||
python3 infra/deploy/release_handoff.py dry-run --artifact-metadata "$metadata"
|
||||
- name: State that no deployment was performed
|
||||
run: |
|
||||
echo 'DEPLOYMENT STATUS: NOT DEPLOYED'
|
||||
echo 'This workflow checks source provenance and may inspect artifact metadata only.'
|
||||
echo 'It does not download the descriptor ZIP, open SSH, or invoke the Windows receiver.'
|
||||
echo 'No Windows execution runner or automatic runtime binding has been verified.'
|
||||
@@ -214,10 +214,16 @@ Docker state, UFW rule details, and protected file metadata were not verified.
|
||||
The descriptor remains unsigned trace metadata, not cryptographic
|
||||
attestation.
|
||||
- A separate `deploy-handoff.yaml` runs after a successful release and checks
|
||||
the source run and stale-main guards. It is dry-run only. It reads artifact
|
||||
metadata through `gitea-api` only if that helper is available in the job
|
||||
image; otherwise it reports metadata and host handoff as unverified. It does
|
||||
not download artifact ZIPs, connect to SSH, or apply a release. The original
|
||||
the source run and stale-main guards. Its job is explicitly
|
||||
`NOT DEPLOYED - handoff status only`; a green result is not a deployment. It
|
||||
reads artifact metadata through `gitea-api` only if that helper is available
|
||||
in the job image; otherwise it reports metadata and host handoff as
|
||||
unverified. It does not download artifact ZIPs, connect to SSH, or apply a
|
||||
release. No repository workflow binding to a Windows runtime starts the receiver;
|
||||
external Windows runner/service inventory has not been verified. The client
|
||||
currently requires an explicit process running `receive_external.py` with
|
||||
the release tuple to open the SSH session. Image release is automated, but
|
||||
production deployment is not yet automatic CD. The original
|
||||
audited `gitea-api` helper lacks binary output and safe 302 handling; the
|
||||
current PR carries a tested patch and host-side artifact verifier, but
|
||||
neither is installed. No deploy key, fixed SSH entry, extra sudo rule, or
|
||||
|
||||
@@ -35,6 +35,38 @@ the response, and refuses to overwrite an existing file. The installer checks
|
||||
the exact audited helper fixture hash before applying its patch. The helper
|
||||
and source code are not installed on the VPS by this PR.
|
||||
|
||||
## Automation boundary: deployment is not configured
|
||||
|
||||
The automatic chain currently ends at release publication:
|
||||
|
||||
1. Successful `main` CI triggers image builds and publishes digest references
|
||||
plus the release descriptor artifact.
|
||||
2. `deploy-handoff.yaml` verifies the source run and may read artifact metadata.
|
||||
Its job is explicitly status-only: **NOT DEPLOYED**. It does not download
|
||||
the descriptor ZIP, call the Windows client, open SSH, or invoke the root
|
||||
receiver. A green result means only that this status check completed.
|
||||
3. The fixed receiver is physically started only when a Windows process runs
|
||||
`infra/backup/receive_external.py` with the release run ID, commit, and
|
||||
descriptor digest. That command opens the owner's SSH session to the fixed
|
||||
root receiver. No repository workflow binding starts it; external Windows
|
||||
runner/service inventory has not been verified.
|
||||
|
||||
Therefore production CD is not yet automatic. A runner label only routes a
|
||||
job; it does not prevent a pull-request workflow from requesting that label.
|
||||
Before unattended cutover, the owner must choose an execution design that
|
||||
demonstrably prevents untrusted PR jobs from reaching the Windows host. A
|
||||
dedicated persistent host-mode runner with D: data and SSH access is unsafe
|
||||
while general repository PR workflows can target it. Acceptable designs
|
||||
include an isolated one-job executor exposed only after an external controller
|
||||
validates the trusted release event and exact run/commit/artifact tuple, or a
|
||||
separate protected deployment repository with no untrusted PR trigger/write
|
||||
path. In either design, the fixed receiver must report its ACK and SSH result
|
||||
before deployment is marked successful. Gitea 1.25 documents Windows runner
|
||||
installation and service operation in its
|
||||
[act_runner guide](https://docs.gitea.com/1.25/usage/actions/act_runner).
|
||||
No such isolation/controller, Windows runner, registration, token, service,
|
||||
SSH credential, or workflow binding has been verified or installed by this PR.
|
||||
|
||||
## External backup and cutover
|
||||
|
||||
The fixed root release receiver accepts only a bounded protocol request over
|
||||
|
||||
@@ -6,6 +6,18 @@ private keys, secret material, or raw process environments.
|
||||
|
||||
## Required before release use
|
||||
|
||||
- Decide whether unattended production CD is acceptable. It currently is not
|
||||
configured: `deploy-handoff.yaml` is metadata/status-only and reports
|
||||
`NOT DEPLOYED`; the Windows receiver starts only from an explicit owner-run
|
||||
CLI command. Automatic activation requires a secure Windows execution path
|
||||
available only to a validated trusted release. A `runs-on` label is routing,
|
||||
not authorization; a persistent host-mode runner sharing D: and SSH files
|
||||
must not be exposed to general repository PR workflows. Before enabling CD,
|
||||
choose an isolated one-job executor gated by an external validator, or a
|
||||
separately protected deployment repository with no untrusted PR trigger or
|
||||
write path. Verify that it validates repository, workflow, event, branch,
|
||||
run, commit, and artifact digest, then reports receiver ACK and SSH success.
|
||||
No such runtime isolation or binding exists in this PR.
|
||||
- Confirm the registry package names and least-privilege writer/pull access for
|
||||
`admin/akyldash/backend` and `admin/akyldash/opensearch`; record digest
|
||||
retention for the rollback window.
|
||||
|
||||
@@ -121,6 +121,8 @@ class ReleaseWorkflowTests(unittest.TestCase):
|
||||
|
||||
def test_deploy_handoff_is_dry_and_uses_the_source_release_run_id(self):
|
||||
workflow = (ROOT / ".gitea/workflows/deploy-handoff.yaml").read_text(encoding="utf-8")
|
||||
self.assertIn("name: Production handoff status (not deployed)", workflow)
|
||||
self.assertIn("name: NOT DEPLOYED - handoff status only", workflow)
|
||||
self.assertIn('workflows: ["Release production images"]', workflow)
|
||||
self.assertIn("branches: [main]", workflow)
|
||||
self.assertIn("types: [completed]", workflow)
|
||||
@@ -134,6 +136,10 @@ class ReleaseWorkflowTests(unittest.TestCase):
|
||||
self.assertNotIn("AKYLDASH_DEPLOY_SSH_KEY", workflow)
|
||||
self.assertNotIn("docker.sock", workflow)
|
||||
self.assertIn("host handoff are not verified", workflow)
|
||||
self.assertIn("DEPLOYMENT STATUS: NOT DEPLOYED", workflow)
|
||||
self.assertIn("No Windows execution runner or automatic runtime binding has been verified.", workflow)
|
||||
self.assertNotIn("receive_external.py", workflow)
|
||||
self.assertNotIn("akyldash-production-windows", workflow)
|
||||
|
||||
def test_source_guards_reject_wrong_event_or_stale_main(self):
|
||||
valid = dict(
|
||||
|
||||
Reference in new issue
Block a user