@hulumi/drift
v1.2.0
Published
Local-first drift classifier — distinguishes provider-API churn from console break-glass from genuine IaC drift via 5 pluggable adapters (4 AWS + 1 GitHub webhook fallback). Verdict logic mirrors HulumiDrift.tla HardenedVerdict exactly. v1.1 adds GithubWe
Readme
@hulumi/drift
Local-first drift classifier for Pulumi stacks. Distinguishes
provider-API churn from console break-glass from genuine IaC drift via
four pluggable adapters whose composition mirrors HardenedVerdict in
HulumiDrift.tla
(upstream planning corpus) exactly.
Quick-start
import {
DriftClassifier,
AutomationApiAdapter,
CloudTrailAdapter,
ProviderVersionAdapter,
GitLogAdapter,
} from "@hulumi/drift";
import { simpleGit } from "simple-git";
const classifier = new DriftClassifier({
adapters: {
automationApi: new AutomationApiAdapter({ preview: runPulumiPreview }),
cloudTrail: new CloudTrailAdapter({ lookup: cloudTrailLookup }),
providerVersion: new ProviderVersionAdapter({ fetcher: pinnedVsLatest }),
gitLog: new GitLogAdapter({ git: simpleGit(), paths: ["pulumi/**/*.ts"] }),
},
probe: cloudTrailDeliveryProbe,
});
const verdict = await classifier.classify(
"urn:pulumi:dev::project::stack",
"urn:pulumi:dev::project::aws:s3/bucketV2:BucketV2::my-bucket",
);
console.log(verdict.source, verdict.confidence);Verdict matrix
| # | Snapshot | Source | Confidence |
| --- | --------------------------------------- | ----------------- | ---------- |
| 1 | !mutated | None | none |
| 2 | mutated && eventDelivered | ConsoleBreakGlass | high |
| 3 | mutated && eventInTransit | Unknown | low |
| 4 | mutated && providerDrift && !event* | ProviderApiChurn | medium |
| 5 | mutated && !provider drift && !event* | Unknown | low |
Row 4's medium ceiling is TLA+-proven (SafetyRealistic invariant).
Security guarantees
- S2 — cache files written with
0o600; ownership-mismatched files are treated as absent. Seetests/cache-permissions.test.ts. - S3 — URNs validated via
urn-sanitize.tsbefore reaching git;simple-gitargv-based call form. Nochild_process.exec. Seetests/shell-injection.test.ts. - S7 — cache TTL is the rate-limit; within TTL repeat calls return
cached verdict. See
tests/rate-limit.test.ts. - E1 — probe wraps
p-timeout+AbortSignal; on timeout returnsUnknown / lowwithprobeFailedAt. Seetests/probe-timeout.test.ts. - E4 — CloudTrail principal filter requires the FULL
hulumi:iac-role=truetag; bareiac-role=trueis rejected. Seetests/namespace-rejection.test.ts. - E5 —
GitLogAdapter.available()isfalseon shallow clones; classifier degrades toUnknown / lowwith remediation. Seetests/shallow-clone.test.ts.
