Repository navigation
Separate sanitized AWS examples from deployment - #1540
ChristianPavilonis wants to merge 7 commits into
Conversation
prk-Jr
left a comment
There was a problem hiding this comment.
Requesting changes for one blocking defect; the other comments are non-blocking.
Blocking: deploy/examples/native-aws-workload/example-envelope.json fails the runtime's own integrity check. Run through VerifiedConfigBlob::parse (the path settings_from_config_blob uses at Axum startup), it is rejected with "app-config blob failed integrity verification": the stored sha256 (5d237581…) does not match the canonical hash of data (2c2f8a22…). The cause is tinybird.access_sample_rate: the file has 0, while the CLI emits 0.0 for this f64 field, as example-noindex-envelope.json does, and the canonical form distinguishes integer from float. With the hash recomputed, the content passes full settings validation, so only the checksum is stale. Details inline.
What I checked and found consistent: store-bindings TOML vs the pinned EdgeZero NativeStoreBindings/AppConfigAgentSettings/SecretsManagerSettings schema; logical store IDs vs edgezero.toml; every EDGEZERO__ADAPTER__* key is consumed; the documented ts config push flags exist; forwarded-header trust (ALB/CloudFront to EdgeZero x-forwarded normalization); all 40 AWS resources depend directly on draft_gate (brace-balanced parse); DynamoDB IAM actions/partitions vs the Axum backend's actual calls, and the table layout vs validate_table.
Not verified here: Terraform runs (the hosted offline-checks job passed at this head), and live-AWS behavior (Fargate volume ownership, Agent with a read-only root filesystem, the execution-role aws:SourceArn condition).
| } | ||
| }, | ||
| "generated_at": "2026-10-20T17:37:22Z", | ||
| "sha256": "5d2375814c35b803ec497d6dec382abce22dd11719021527134cf9cc09544491", |
There was a problem hiding this comment.
Blocking: this envelope fails runtime integrity verification.
BlobEnvelope::verify recomputes canonical_data_sha256(data) and the result does not match this field: stored 5d2375814c…, computed 2c2f8a221b…. I ran the fixture through trusted_server_core::config_payload::VerifiedConfigBlob::parse, the same path settings_from_config_blob uses at startup, and it is rejected with "Trusted Server app-config blob failed integrity verification". example-noindex-envelope.json passes the same probe.
terraform.tfvars.example points config_envelope_file here, so a task started from it would never become healthy. The Terraform checks still pass: envelope_valid only regex-checks sha256, and envelope_reject_invalid_checksum only covers malformed hex. Yet draft.tftest.hcl describes this as a supported CLI envelope fixture.
Suggested fix:
- Regenerate the file with
ts config push … --local --no-envand keep it byte-exact. Don't reformat it afterwards; the minified noindex fixture survived. - Add a native test under
crates/trusted-server-core/tests/that runs both fixtures throughVerifiedConfigBlob::parse(...)andinto_settings(...)with a fictional secret store. Terraform cannot recompute this canonical hash, so this protection has to live in Rust.
| "auction_dataset": "auction_events_raw", | ||
| "access_enabled": false, | ||
| "access_dataset": "access_logs_raw", | ||
| "access_sample_rate": 0, |
There was a problem hiding this comment.
Root cause of the checksum mismatch above: the CLI emits this f64 as 0.0, as example-noindex-envelope.json does, and the stored hash was computed over that. Swapping in the noindex tinybird object reproduces the stored hash exactly. Rewriting it as 0 changes the canonical bytes, because the canonical form distinguishes an integer from a float. Recomputing the hash over the current content passes full settings validation, so only the checksum is stale.
| on: | ||
| pull_request: | ||
| paths: | ||
| - 'deploy/examples/native-aws-workload/**' |
There was a problem hiding this comment.
Non-blocking: deploy/examples/native-ec-dynamodb/ has no CI. These path filters and steps cover only native-aws-workload/, and no other workflow touches deploy/examples/, so a format error, broken HCL or stale lock file in the DynamoDB root would merge green.
pbs-example.yml sets the precedent: add the path, then run fmt -check, init -backend=false -input=false -lockfile=readonly, validate and a git diff --exit-code on its lock file. test-workflow.mjs would still pass.
| } | ||
|
|
||
| resource "aws_iam_role_policy" "ec" { | ||
| name = "trusted-server-native-ec" |
There was a problem hiding this comment.
Non-blocking: the fixed inline-policy name can collide. PutRolePolicy replaces an inline policy with the same name. If two applications of this root, for example staging and production namespaces, target the same task_role_name, the second apply silently replaces the first grant and the first namespace loses table access. Destroying either one would also delete the other's policy.
Suggest deriving the name from the table or namespace, for example "trusted-server-native-ec-${var.table_name}".
|
|
||
| The required `owner` owns the table, both reserved namespace partitions, allocator continuity, retention decisions, ongoing cost and eventual decommissioning. The task role remains owned by its workload. Removing the workload must not remove this table. Before retiring a role, remove or transfer this root's inline-policy attachment so retained state does not reference a deleted role. | ||
|
|
||
| The table has `PAY_PER_REQUEST` capacity, string keys `pk` and `sk`, service TTL `ttl_epoch_s`, default service-managed encryption, deletion protection and Terraform `prevent_destroy`. It has no indexes or replicas. TTL is not an immediate deletion guarantee. The backend enforces logical expiration with `expires_at_ms`. |
There was a problem hiding this comment.
Non-blocking: in the AWS provider, server_side_encryption { enabled = true } selects the AWS-managed KMS key aws/dynamodb. The default, which the console shows as DEFAULT, is the AWS-owned key and corresponds to omitting the block or setting enabled = false. So "default service-managed encryption" doesn't describe what main.tf creates. The difference matters for KMS charges and for the boundary review this README asks for. Suggest correcting the wording, or removing the block if the default is what's intended.
|
|
||
| ## Review and local checks | ||
|
|
||
| Copy `terraform.tfvars.example` to an approved, untracked input location and replace every illustrative identifier. Review the account, region, retained state key, task role, table/data lifetime and both namespace partitions. A namespace is not a secret and must not contain customer data. |
There was a problem hiding this comment.
Non-blocking: this root has no .gitignore, unlike native-aws-workload/ and deploy/pbs-example/, and the repository root doesn't ignore Terraform files. Running terraform init here leaves .terraform/, including .terraform/terraform.tfstate with the S3 backend bucket, key and region, as untracked and not ignored. A copied terraform.tfvars would be in the same state. Suggest copying the workload root's .gitignore.
| @@ -0,0 +1,77 @@ | |||
| # Native AWS workload example | |||
|
|
|||
| This example shows an Axum workload on AWS Fargate with AppConfig, Secrets Manager, an ALB and optional protected CloudFront Geo. It derives from the native workload Terraform and its reviewed deployer extraction. Operational deployment ownership stays in [trusted-server-deployer](https://github.com/stackpop/trusted-server-deployer), under `terraform/aws/` and `scripts/aws/`. | |||
There was a problem hiding this comment.
Non-blocking: this link points to stackpop/trusted-server-deployer, which is a private repository, and nothing on the base branch references it. Public readers get a 404 at exactly the place this README, and lines 54 and 75, say saved-state, header continuity and plan validation are enforced. Suggest stating the requirement without the link, or noting that the deployer is a separate access-controlled repository.
|
|
||
| The root attaches the policy to `task_role_name`; that is not enough when the existing task boundary explicitly denies DynamoDB. Have the boundary owner review both its action ceiling and its constrained allow statements, then review the task inline policy. Do not remove the boundary, broaden the execution role, or weaken the deny to get a successful test. Other policies can still deny the calls. | ||
|
|
||
| `ec_storage` replaces the former `runtime_environment` output. Publish this non-secret object as `[ec.storage]` in the existing Trusted Server app-config BlobEnvelope before launching an application built with `aws-dynamodb-ec`. Use `terraform output -json ec_storage` only against the separately approved retained state; this guide does not run it. Keep the exact table and namespace unchanged. Config publication is the existing `ts config push`/AppConfig workflow, not container environment injection or another envelope format. The old enabled `TS_EC_DYNAMODB_ENABLED` launch contract now fails before readiness, even alongside new config. Remove the old selection and binding variables after preparing publication. External consumers of the removed output must migrate with this change. The ordinary AWS workload credential chain still supplies task credentials. Do not add access keys to Terraform or the task definition. |
There was a problem hiding this comment.
Nit: in this repository the example is new, so there is no "former runtime_environment output" for external consumers to migrate from. The TS_EC_DYNAMODB_ENABLED sentence is accurate, since ec_kv.rs rejects it. Suggest dropping the migration sentences.
| // Retire the old service before its final listener association is removed. | ||
| // Keeping a zero-desired service would still require that association for every | ||
| // ECS UpdateService, including the scale-down itself. | ||
| moved { |
There was a problem hiding this comment.
Nit: on a fresh root this moved block does nothing; it only matters for state from the original demo. The comment above it describes retiring a service rather than the address move. This file also mixes // and # comments, while the rest of the example uses #.
Summary
Draft baseline review unit. Not a current-main merge candidate, deployment approval or completed current-head CI claim.
Baseline and sequence
Head:
ee7f68fcf25cc2954ffc0204301c0c264f1ce558. Base:baseline/native-runtime-20261110.Historical main anchor:
2dd968aeebeb2cc0d5110115f64e0ad58e2e1d13. Original demo: TS2423a2ed plus separately preserved dirty inputs. Matching EdgeZero: draft431, exact revision83d7a6296d285e135c4ea70021b19e6c8dca7e9f.The user selected compatible-baseline cleanup. Current-main integration with EdgeZero462 and the authenticated-forwarder incompatibility are deferred. Preserve current-main PR1525/1526 ready and1527/1528 draft, with their existing bases. No excluded1499 or independent1506 implementation, relay/privacy experiment, new transport fallback, group/codec/phase design or operational deployment is included.
Changes
Closes
Refs #1530. This unit completes one part of the baseline extraction and does not close the overall tracker on its own.
Spec
Not a new feature. This is extraction of existing demo behavior and bounded build/caller corrections. Original native and EC storage design/review records remain in the baseline where applicable; they are not presented as approval of later combined source. No new forwarding, consent, timer or provider policy is designed here.
Test plan
The fictional workload config also passes real TS CLI typed strict validation with env overlays disabled. The separate DynamoDB example passes backend-free initialization and Terraform validation, without contacting AWS.
Workflow2 cases, actionlint, Terraform format/backend-free initialization and credential-free closed-gate mock plans pass. All40 workload AWS resources retain the closed production gate. One trailing fixture blank line was removed for diff hygiene. No cloud apply, real state, credentials or operator identities are imported.
The b67ffc6 baseline checkpoint has passing documented local gates: Fastly/default/reuse/native/Cloudflare/Spin suites, all adapter strict lint lanes, 17 cross-adapter parity cases, 1252 JS cases, CLI suites, formatting, clock/digest/proposal checks and changed-lines domain lint. Passing checks at121ebcc36 are reused only for unchanged relevant inputs; the final follow-up covers the CLI test-import and documentation-only corrections. These results are not a substitute for this PR's current-head hosted checks.
Checklist
Operational Terraform remains in trusted-server-deployer. Local checks and prototype tests do not qualify cloud access, fleet durability or a live publisher.
Hosted docs-build correction
The first hosted format-docs job caught an additional site-build gate that the original local formatter checkpoint had not run: a relative link from the native EC guide to a Terraform example outside the site. Native EC correction8b11dbad3 replaces it with the plain repository path; no dead-link check is disabled. That docs-only correction is carried through the existing upper PR identities. Native EC and final integration8985b111 both pass docs ESLint and VitePress build; the final docs formatter also passes. Runtime, dependency, image-build-context and test inputs are unchanged from b67ffc6, so their prior exact-input proofs are reused. Hosted current-head checks still control readiness.
Startup negative-probe correction
A hosted native EC case failed the no-listener probe while its child logged the expected startup validation failure. The old log has no socket endpoints, so the failure's exact subtype is not claimed confirmed. A separate controlled Linux reproduction demonstrates a successful TCP self-connection with no listening server. Native correction8490c691d distinguishes equal local/peer endpoints from a real listener; actual socket controls prove the self-connection is excluded and a real listener is still detected. Nonzero exit, expected diagnostic, secret-redaction and the original startup deadline remain required. This changes only the acceptance fixture, not production admission, transport or trust.
The earliest native unit and final9356c557 default/all-feature acceptance checks and strict lint pass, including both controls and the original failure case. Ignores remain explicit; earlier separately executed celld proof is not relabeled as a new ignored-case run. Correction is merged upward through existing PR identities without force-pushing or retargeting. Current-head hosted checks must pass; the old failure is retained rather than rerun-only waived. Runtime/API/dependency inputs remain unchanged. A fresh exact9356 producer build and real runtime smoke now pass: image
sha256:65a735d38e9dbc0573d0f6068a8b261bd202c43aea05085c2b2d6bccc91ebdbd, linux/amd64 UID/GID10001, including startup rejection and in-flight SIGTERM drain. Prior b67 image receipts remain separate; no image was pushed. All local parent runners are complete.Browser CI host compatibility
Preserved older browser failures show Playwright1.58.2 rejecting ubuntu-latest's new Ubuntu26.04 image before browser installation; later missing-executable failures are consequences, not passing browser tests. Nativeb1216763a pins only the browser job to ubuntu-24.04, leaving dependency versions, tests and assertions unchanged. Direct Actionlint1.7.12 passes at the owning native and final integration points; the first shim-only attempt could not run because no global version was configured, and is not counted as lint proof. No global tooling was changed. The only9356 ->ee7 delta is this workflow host/comment; runtime, Cargo, docs, tests and Docker-context inputs are unchanged. Actual browser execution on the supported hosted runner remains pending and must pass before readiness. No waiver or browser skip.