import { type Result } from "@fjall/generator"; /** * A raw AWS IAM policy statement, preserved verbatim from the captured policy. * Triage never reshapes a kept statement — survivors are re-put byte-for-byte * (minus the stripped quarantine deny), so any field we do not model * (NotPrincipal, NotAction, NotResource, …) survives intact. Reshaping a kept * statement through a typed schema would silently widen or narrow access. */ export type RawPolicyStatement = Record; /** * The captured policy envelope. Only `Statement` is load-bearing for triage; * every other top-level field (Version, Id, …) is preserved through the index * signature so the re-put keeps the document's original shape. */ export interface RawPolicyDocument { Statement: RawPolicyStatement[]; [key: string]: unknown; } export type StatementClassification = "keep" | "strip" | "keep-flagged"; export interface ClassifiedStatement { statement: RawPolicyStatement; classification: StatementClassification; /** British-English reason the statement was kept, stripped, or flagged. */ reason: string; } export interface BucketPolicyTriage { /** * The document to re-put: the captured envelope (Version/Id preserved) with * Statement narrowed to the survivors. `null` when nothing survives the strip * — the caller must then synthesise an enforceSSL-only policy (or leave the * bucket policy-less); re-putting an empty Statement array is invalid in AWS. */ sanePolicyDocument: RawPolicyDocument | null; /** Survivors (Allow grants, conditioned denies, enforceSSL) — re-put verbatim. */ keptStatements: RawPolicyStatement[]; /** Stranded quarantine denies removed by the triage. */ strippedStatements: RawPolicyStatement[]; /** Broad denies kept but surfaced for review (could mask a quarantine). */ flaggedStatements: RawPolicyStatement[]; /** Whether the captured policy carried an enforceSSL TLS-only deny. */ hadEnforceSsl: boolean; classifications: ClassifiedStatement[]; /** British-English triage notes for the operator / PR reviewer. */ notes: string[]; } /** * True when the statement is the enforceSSL TLS-only deny — a `Deny` carrying * the `aws:SecureTransport: false` condition. This is the exact predicate behind * {@link BucketPolicyTriage.hadEnforceSsl}, exported so `toResourcePolicyStatements` * can exclude enforceSSL from the typed `resourcePolicyStatements` array using * the same rule (the S3Bucket construct always re-adds it via `enforceSSL: true`, * so listing it would double-render). Triage and converter share one source. */ export declare function isEnforceSslStatement(statement: RawPolicyStatement): boolean; /** * Structurally classify a captured S3 bucket policy and separate the stranded * quarantine deny from statements worth restoring. * * The captured policy is the raw `GetBucketPolicy` JSON string taken by * {@link unlockBucket} BEFORE it deleted the live policy — detection of the * quarantine is behavioural (an AccessDenied proxy), so this is the first code * to classify the policy structurally. The result feeds both the SDK re-put (a * live policy document) and, later, the code-first reconciliation. * * Strips conservatively: only a high-confidence TOTAL lockout (denies all S3, * every principal, the whole bucket, no condition) is removed. Any broad deny * scoped by principal, resource, or condition is KEPT and flagged for review — * stripping it would silently widen access, whereas keeping a real lockout fails * loudly on re-put and is recoverable. Known limit: a quarantine spelled as an * enumerated concrete-action list (rather than `s3:*`/`NotAction`) is flagged, * not stripped — the canonical quarantine uses `s3:*`. * * Fails closed: malformed JSON, a non-object envelope, a non-object statement, * or an unrecognised Effect returns a failure rather than guessing — the * operator still holds the captured forensic JSON to re-put by hand. * * Every failure `Error.message` is pre-masked at construction: the JSON-parse * detail and the unrecognised-Effect value can embed captured-policy credential * fragments, so callers and downstream sinks (the webapp audit ledger / UI) must * NOT re-mask. See the credential-masking standard, § "Pre-masked producers". */ export declare function triageBucketPolicy(capturedPolicyJson: string): Result;