import { type Result } from "@fjall/generator"; /** * The AWS-account/region context a standalone per-zone domain deploy session's * inline policy is scoped to. `zoneName` MUST be the registered domain * record's own `name` spelling (fjall-config.json) — the stack-name * derivation PascalCases the given string verbatim and IAM ARN matching is * case-sensitive, so a caller-normalised or user-typed variant would deny * the zone's own stack (fail-closed, but loud at deploy time instead of * here). Callers necessarily hold the record already: `accountId`/`region` * are its home pin — carried for caller-intent clarity, though the policy's * ARNs deliberately wildcard both segments (see the builder body). */ export interface DomainSessionContext { zoneName: string; region: string; accountId: string; partition: string; } /** * Build a defence-in-depth inline session policy that narrows a per-zone * domain deploy session's DIRECT CloudFormation mutation to the target zone's * own stacks — the F5 sibling of `buildDeploySessionPolicy` * (`../application/deploySessionPolicy.js`), inheriting its DENY-list * rationale wholesale: the session must keep synth lookups, asset uploads and * `iam:PassRole`, so we lead with `Allow * on *` and Deny only foreign * mutation. It also inherits the same accepted v1 limitation that session * policies do not propagate across `sts:AssumeRole` — the cfn-exec role is * confined by the Phase E permission boundary, not by this policy. * * Scope note: this builder exists for zones homed in the ORG-ROLE account, * where the standalone lane would otherwise run under the unscoped org * session. A FOREIGN-pinned zone needs nothing from here — its session is * minted per-home against that account's M1-narrowed `FjallDeploy` role (the * 2d routing factory), and IAM itself is the narrowing. * * Differences from the application builder, each derived from what a domain * deploy actually does: * - The CFN NotResource names the zone's stacks EXACTLY (no prefix wildcard): * `getDomainStackName(zone)` plus its paired us-east-1 certificates stack * (`getDomainUsEast1CertificatesStackName`) — CloudFront viewer certificates * only mint in us-east-1, so the pair spans two regions by construction — * plus CDKToolkit. The ARNs' region/account segments are wildcarded (see the * builder body), so each stack needs exactly one entry regardless of which * regions it spans. Exact names close the app builder's prefix-wildcard * class of over-grant across DISTINCT stacks. (getDomainStackName is not injective * — it strips dots before PascalCasing, so `dev.fjall.io` and * `devfjall.io` share one stack name — but two such zones in one * account+region share the PHYSICAL stack too, which no ARN-scoped policy * can separate; that non-injectivity is a pre-existing registration-time * concern, not a session-policy one.) * - ECR mutation is denied on `Resource: *`, not NotResource-fenced: a domain * deploy pushes no images, so there is no repository it legitimately * mutates. * - Route53 record mutation is NOT fenced here: record writes flow through * CloudFormation's cfn-exec role (out of session-policy reach, above) and * the takeover gate's release path, which is collision-assessed per zone. * Fencing `ChangeResourceRecordSets` by hosted-zone id would need a live * lookup before the session exists — accepted v1 limitation, same class as * the app builder's. * * Fails closed when the serialised policy would exceed the packed-safe STS * session-policy budget. */ export declare function buildDomainSessionPolicy(ctx: DomainSessionContext): Result;