Status as of v1.3.2 plus ticket #24: this doc is the contract for
the remaining real-AWS integration tests. The AccountFoundation sandbox
and Startup-Hardened success paths now have real Pulumi Automation API
up/assert/destroy tests with AWS API reachability checks and KMS cleanup
assertions. The drift-classify lane now has one real-AWS S3 console-drift
proof with cache-hit verification. The AccountFoundation
failure-injection cleanup scenario and remaining drift real-AWS
scenarios remain separate runbook work (hulumi-integration-real-aws,
candidate for a later train).
Why a roadmap and not implementation? The sandbox-AWS deploy rig is a 200–400 LOC undertaking per scenario, requires a configured Pulumi backend + AWS access + a stable cleanup invariant, and takes 5–15 minutes per test run. Authoring it in the same milestone as four unrelated public-launch hygiene fixes was the wrong shape; this doc carves it off cleanly.
| Test file | Status | Roadmap section |
|---|---|---|
packages/baseline/tests/integration/account-foundation.integration.test.ts |
sandbox + startup success paths implemented; it.todo ×1 |
#account-foundation |
packages/drift/tests/integration/drift-classify.integration.test.ts |
S3 console-drift smoke implemented; it.todo ×2 |
#drift-classify |
Both files keep one always-on it() that asserts the
HULUMI_INTEGRATION=1 skip-gate is in place. That gate is a regression
target; if a future change lands a real test that runs unconditionally,
the gate-invariant catches it.
Anything that lands real-AWS coverage will need:
- Pulumi backend in the workflow runner. Prefer
PULUMI_BACKEND_URLas a repository secret for self-managed S3 state;PULUMI_ACCESS_TOKENremains an optional Pulumi Cloud alternative. The workflow refuses both at once. - Sandbox-AWS OIDC role. Already wired
(
aws-actions/configure-aws-credentials, SHA-pinned in M2). - Stack lifecycle:
pulumi up→ wait → assert →pulumi destroy. Cleanup must run on both success and failure paths (afterEach/try-finally). Pulumi Automation API exposes this viaLocalWorkspace+Stack.up()+Stack.destroy(). - AWS API polling for resource readiness — every poll bounded by an explicit timeout, every retry budget-bounded.
- Tag invariant: every fixture stack tags resources with
hulumi:iac-role=trueso the classifier sees them as IaC-managed. - Test artifact cleanup: after the test run, no Pulumi
checkpoints /
.pulumi/directories leak into the working tree. The existing.gitignorealready coverspackages/baseline/**/.pulumi/andpackages/baseline/tests/integration/.tmp/; new tests must honour those paths. - Open-source safety: no static credentials, no public ingress,
no public S3 buckets, no public repos, no public sandbox account
identifiers, and no full state export in logs. The sandbox role
should use
docs/deployment/weekly-integration-iam-policy.json, not administrator access.
Current implementation:
packages/baseline/tests/integration/account-foundation.integration.test.tscreates a short-lived inline Pulumi Automation API stack whenHULUMI_INTEGRATION=1,HULUMI_TIER=sandbox, one Pulumi backend is configured, andHULUMI_IAC_ROLE_ARNis set.- The test runs
Stack.up(), asserts real provider outputs through AWS API calls for CloudTrail, Config, GuardDuty, Security Hub, and the four KMS keys, then always callsStack.destroy()andremoveStack()inafterAll. - After destroy, the test checks that the four test-created KMS keys are
not left in
Enabledstate. AWS pending-deletion state counts as cleaned up. - The test suppresses Pulumi output so logs do not print state, account identifiers, or backend details.
Remaining target: the separate failure-injection cleanup scenario.
Pre-conditions:
PULUMI_BACKEND_URLorPULUMI_ACCESS_TOKENconfigured- AWS OIDC role assumed (sandbox account)
Stack shape: a Pulumi program that imports @hulumi/baseline and
constructs:
new AccountFoundation("integration-test", {
tier: "sandbox",
iacRoleArn: process.env.HULUMI_IAC_ROLE_ARN!,
region: "us-east-1",
});Expected sub-resources (per docs/components/account-foundation.md):
- CloudTrail trail with multi-region + log-file validation
- Config recorder + delivery channel
- GuardDuty detector (status: ENABLED)
- SecurityHub subscription (status: SUBSCRIBED)
- IAM password policy (status: applied)
- KMS key with rotation enabled
Polling: for each sub-resource, poll the AWS API until status is the expected value, with a per-resource timeout of 5 minutes (capped at 15 min total wall-clock).
Verdict: every asserted sub-resource reports the expected state
within the budget, then pulumi destroy runs to completion without
enabled KMS orphans.
Cleanup invariant: even if any assertion throws, Stack.destroy()
runs in a finally block. The post-test git status shows a clean
working tree.
Wall-clock estimate: 12–15 minutes per run.
Same shape as Test 1, with tier: "startup-hardened". The test creates
a scoped S3 server-access-log target bucket for AccountFoundation's
internal hardened log bucket, deletes that bucket in cleanup, and
asserts CloudTrail multi-region/log-file-validation behavior alongside
the common CloudTrail, Config, GuardDuty, Security Hub, and KMS checks.
Wall-clock estimate: 15 minutes per run.
Deliberately trigger a stack-up failure (e.g. by passing an invalid
KMS key alias that fails at apply time), then assert that
Stack.destroy() still runs and removes whatever sub-resources DID
make it ACTIVE before the failure.
Wall-clock estimate: 5–8 minutes per run.
Test 1 — console drift detected: ConsoleBreakGlass/high after deliberate mutation by non-IaC principal
Current implementation:
packages/drift/tests/integration/drift-classify.integration.test.tscreates one short-lived Pulumi-managed S3 bucket whenHULUMI_INTEGRATION=1and one Pulumi backend is configured.- The test mutates bucket tags through the AWS SDK, waits for the
CloudTrail
PutBucketTaggingevent, classifies the bucket withDriftClassifier, and expectsConsoleBreakGlass / high. - The same test calls
classify()a second time inside the cache TTL and asserts the adapters/probe were not called again. afterAllalways runsStack.destroy(), removes the Pulumi stack, and deletes the local Pulumi work directory.
Remaining target: broader fixture coverage for non-S3 resources and failure-injection teardown.
Pre-conditions:
- Sandbox Pulumi stack containing a single
SecureBucketalready deployed (or deployed as part of the test setup) - AWS API access via a non-IaC principal (different from the IaC role that deployed the bucket)
Mutation: as the non-IaC principal, modify a tag on the SecureBucket
(e.g. aws s3api put-bucket-tagging --bucket <name> --tagging '{...}')
or change a permission. This emits a CloudTrail event tagged with the
non-IaC principal's ARN.
Wait: CloudTrail event delivery latency is region-dependent (typically 1–5 minutes). Poll the bucket's history until the event appears.
Expected verdict: DriftClassifier.classify() returns
{ source: "ConsoleBreakGlass", confidence: "high" }.
Cleanup: the deliberate mutation is reverted as part of teardown. The IaC stack is destroyed.
Wall-clock estimate: 5–8 minutes per run.
Pre-conditions: stack pinned to an OLDER @pulumi/aws than the
latest published version. The provider-version adapter compares pinned
vs latest from the npm registry.
Verdict: classifier returns
{ source: "ProviderApiChurn", confidence: "medium" }. The medium
confidence ceiling is TLA+-proven (per HulumiDrift.tla).
Wall-clock estimate: 2 minutes per run (mostly local + one npm registry call; minimal real AWS required).
After Test 1's verdict is computed and cached (in
.hulumi/drift-cache/*.json), call classify() a second time within
the TTL. Verify zero AWS API calls happen in the second invocation
(use a recording mock or count CloudTrail Lookup invocations).
Wall-clock estimate: 1 minute per run.
Force classify() to throw mid-execution (e.g. via a probe-timeout).
Assert the test fixture (deployed bucket + IAM role) is still cleaned
up via pulumi destroy.
Wall-clock estimate: 3–5 minutes per run.
When hulumi-integration-real-aws ships:
- The AccountFoundation sandbox smoke is extended with AWS API reachability checks for the expected sub-resources.
- The remaining
it.todo()slots above are replaced with real implementations. - All real-AWS tests gated on
HULUMI_INTEGRATION=1(skip-gate preserved). - All real-AWS tests run cleanly in the weekly workflow.
- Total wall-clock for the weekly workflow stays under 60 minutes.
- No orphan resources after a full success-path run.
- No orphan resources after a failure-injection run.
-
tests/skill-bdd/retains theit.todo-counter regression that catches a future stub re-introduction.
The audit framing was: "tautological tests masquerading as coverage." There are two honest fixes:
- Implement the real test. Best long-term — but a 1–2 week workstream that wasn't in scope for the public-launch hygiene pass.
- Make the gap explicit.
it.todo()reports astodoin vitest, notpassed. A reader who runspnpm -r testsees the gap immediately. A future PR that drops thetodowithout filling in the implementation also fails review.
M3 chose option 2 for #21 + #24 and option 1 for #26 (cooling-off
diff) and #30 (SCP teardown). The latter two were small enough to
ship in this milestone; the former two carve cleanly into a future
runbook tracked here.