First public release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 14:49:02 -04:00
co-authored by Claude Opus 5.5
commit 0526dc283a
14 changed files with 2102 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
+9
View File
@@ -0,0 +1,9 @@
node_modules/
dist/
*.log
.DS_Store
.env
.env.*
!.env.example
.npmrc
dist-cjs/
+6
View File
@@ -0,0 +1,6 @@
stages: [test]
test:
stage: test
image: node:22-alpine
script: [npm ci, npm run build, npm test]
+14
View File
@@ -0,0 +1,14 @@
# Changelog
## 0.1.0 - 2026-09-28
First public release under MIT.
- `checkPlan()` and `formatPlan()` check a deploy plan against a total-volume
budget, a peak-rate ceiling and a destination allowlist.
- `worstCaseBytes()` counts every retry attempt.
- A step reaching a host outside the allowlist is critical however small the
transfer.
- Peak rate is checked separately from total and multiplied by concurrency.
- An unmeasured step is NOT ASSESSED and makes the total a stated lower
bound. The total still fails when the known bytes alone exceed the budget.
+21
View File
@@ -0,0 +1,21 @@
# Contributing
Issues and merge requests are welcome at
https://gitlab.com/extant2000/quiet-deploy.
## Ground rules
- A test that cannot fail proves nothing. If you fix a bug, add a test and
check that it fails against the unfixed code before you submit.
- Measure, don't assume. Two modules with the same line count can still be
different programs.
- Keep dependencies minimal. Every new runtime dependency needs a reason.
- Explain why in comments, not what. The what is already in the code.
- A breaking change needs a major version bump and a note in CHANGELOG.md.
## Before you open a merge request
Run both of these and make sure they pass:
npm run build
npm test
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Extant 2000 LLC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+89
View File
@@ -0,0 +1,89 @@
# QuietDeploy
Check a deployment plan against a network-signature budget before it runs.
QuietDeploy takes the steps of a rollout (what each one contacts, how many
bytes it moves, for how long, with how many retries) and checks them against
a total-volume budget, a peak-rate ceiling and a destination allowlist. It is
pure, with no network and no clock. It sends nothing.
## What it checks and why
A deployment is observable. On a constrained or monitored link, the volume,
the destinations and the timing of what a rollout pulls are a signal in
themselves. The failures tend to be the same three.
1. The pull nobody counted. A build that "just pulls a base image" can move
hundreds of megabytes to a third-party registry. It does not show up in
the plan because nobody wrote it as a step; it is a side effect of one. A
step with `bytes: null` is NOT ASSESSED, never zero. An unmeasured
transfer is not a small one.
2. Egress outside the declared set. An allowlist exists because a deploy
that reaches an unexpected host is either a supply-chain problem or a
leak. That check runs first and stays critical however small the transfer
is. Volume is irrelevant to it.
3. A burst that fits the total and not any window. Ten targets pulling 200 MB
each inside a minute is a different signature from the same traffic over
an hour, and a total-only budget passes both. Peak rate is checked on its
own and multiplied by `concurrency`.
Retries are cost. `worstCaseBytes()` counts every attempt, because a step
budgeted at one attempt is budgeted at its best case. A plan that fits on the
first try and not with retries fails.
When any step is unmeasured, the total is reported as a lower bound, not a
total. A partial sum presented as a total is how a budget check reassures
without checking. The total still fails if the known bytes alone exceed the
budget, since unmeasured steps cannot rescue a plan that is already over.
## Usage
```ts
import { checkPlan, formatPlan, type DeployStep, type SignatureBudget } from '@extant2000/quiet-deploy'
const steps: DeployStep[] = [
{ name: 'pull-base-image', destination: 'registry.example.com', bytes: 200_000_000, durationSeconds: 60, retries: 2, where: 'ci.yml' },
{ name: 'fetch-cli', destination: 'downloads.example.net', bytes: 5_000_000, durationSeconds: 10, where: 'scripts/setup.sh' },
{ name: 'push-app-image', destination: 'registry.example.com', bytes: null, where: 'ci.yml' },
]
const budget: SignatureBudget = {
maxTotalBytes: 2e9,
maxBytesPerSecond: 5e6,
allowedDestinations: ['registry.example.com'],
concurrency: 4,
}
const report = checkPlan(steps, budget)
for (const f of report.findings) console.log(`${f.determination.padEnd(13)} ${f.id}: ${f.summary}`)
// The full evidence-record report for a terminal or CI log
console.log(formatPlan(steps, budget))
```
`checkPlan()` returns a `CapabilityReport` from `@extant2000/evidence-record`.
`worstCaseBytes()`, `peakRate()` and `formatBytes()` are exported as well.
## Sample output
Produced by running the example above (the loop over findings):
```
not-assessed total: 405.0 MB of 2.0 GB accounted for, with 1 step(s) unmeasured
fail pull-base-image: pull-base-image peaks at 13.3 MB/s
fail fetch-cli: fetch-cli contacts downloads.example.net, which is not in the declared set
not-assessed push-app-image: push-app-image moves an unknown volume to registry.example.com
```
The 405 MB total counts both attempts of the base-image pull. The pull fails
the rate check only because four run at once.
## Install
```
npm install @extant2000/quiet-deploy
```
## License
MIT. Copyright (c) 2026 Extant 2000 LLC. See [LICENSE](LICENSE).
+11
View File
@@ -0,0 +1,11 @@
# Security policy
## Reporting a vulnerability
Please report vulnerabilities privately by email to security@extant2000.com.
Do not open a public issue or merge request for a security problem.
Include the affected version, a description of the issue, and steps or a test
that reproduce it if you have them.
We aim to acknowledge every report within 5 business days.
+1504
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
{
"name": "@extant2000/quiet-deploy",
"version": "0.1.0",
"private": false,
"description": "Deployment that holds a defined network-signature threshold.",
"license": "MIT",
"type": "module",
"main": "./dist-cjs/index.js",
"files": [
"dist",
"dist-cjs",
"src",
"README.md",
"LICENSE"
],
"repository": {
"type": "git",
"url": "https://gitlab.com/extant2000/quiet-deploy.git"
},
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist-cjs/index.js"
}
},
"scripts": {
"build": "tsc && tsc -p tsconfig.cjs.json && node -e \"require('fs').writeFileSync('dist-cjs/package.json', JSON.stringify({type:'commonjs'}))\"",
"test": "vitest run",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"typescript": "^5.6.0",
"vitest": "^2.1.0"
},
"dependencies": {
"@extant2000/evidence-record": "^0.1.2"
},
"author": "Extant 2000 LLC",
"homepage": "https://gitlab.com/extant2000/quiet-deploy",
"bugs": {
"url": "https://gitlab.com/extant2000/quiet-deploy/-/issues"
}
}
+227
View File
@@ -0,0 +1,227 @@
/**
* QuietDeploy — check a deployment plan against a network-signature budget
* before it runs.
*
* A deployment is observable. On a constrained or monitored link, the volume,
* the destinations and the timing of what a rollout pulls are themselves a
* signal, and the failures are consistently the same three:
*
* 1. **The unbudgeted pull nobody counted.** A build that "just pulls a base
* image" moves hundreds of megabytes to a third-party registry. It is
* invisible in the plan because it is not a step anyone wrote — it is a
* consequence of one.
*
* 2. **Egress to destinations outside the declared set.** An allowlisted
* egress firewall exists precisely because a deploy that reaches an
* unexpected host is either a supply-chain problem or a leak. A plan
* that cannot enumerate its destinations cannot be checked against one.
*
* 3. **A burst that fits the budget in total and not in any window.** Ten
* targets pulling 200 MB each inside one minute is a very different
* signature from the same traffic spread over an hour, and a total-only
* budget passes both. Peak rate is checked separately from volume.
*
* `retry` is treated as multiplying its step's cost, not as a footnote: a
* step budgeted at its first-attempt size is budgeted at its best case.
*
* Pure: no network, no clock. It sends nothing.
*/
import {
type CapabilityReport,
type Finding,
type FormatOptions,
evidence,
formatReport as renderReport,
} from '@extant2000/evidence-record'
export interface DeployStep {
name: string
/** Host contacted. Checked against the allowlist. */
destination: string
/** Bytes moved per attempt. `null` when unknown — never assumed zero. */
bytes: number | null
/** Seconds this step occupies. Used for the peak-rate check. */
durationSeconds?: number
/** Maximum attempts. A step budgeted at one attempt is budgeted at best case. */
retries?: number
/** Where the step is defined — a CI file, a compose file, a script. */
where: string
}
export interface SignatureBudget {
/** Total bytes the whole rollout may move. */
maxTotalBytes?: number
/** Peak bytes per second in any single step. */
maxBytesPerSecond?: number
/** Hosts this rollout is permitted to contact. */
allowedDestinations?: string[]
/** Steps that may run at once — concurrency multiplies the peak. */
concurrency?: number
}
const fmt = (n: number): string =>
n >= 1e9 ? `${(n / 1e9).toFixed(1)} GB`
: n >= 1e6 ? `${(n / 1e6).toFixed(1)} MB`
: n >= 1e3 ? `${(n / 1e3).toFixed(1)} kB`
: `${n} B`
/** Worst-case bytes for a step: every attempt counts. */
export function worstCaseBytes(s: DeployStep): number | null {
if (s.bytes === null) return null
return s.bytes * Math.max(1, s.retries ?? 1)
}
/** Peak bytes/second for a step, `null` when either input is missing. */
export function peakRate(s: DeployStep): number | null {
if (s.bytes === null || !s.durationSeconds) return null
return Math.round(s.bytes / s.durationSeconds)
}
function stepEvidence(s: DeployStep) {
return evidence.file(s.where, undefined,
s.bytes === null ? 'volume unknown' : fmt(worstCaseBytes(s)!),
`${s.destination}${s.retries && s.retries > 1 ? `, up to ${s.retries} attempts` : ''}`)
}
function stepFinding(s: DeployStep, budget: SignatureBudget): Finding {
const id = s.name
const allowed = budget.allowedDestinations
// Checked first: an unexpected destination is a different KIND of problem
// from a large one, and it stays a finding however small the transfer is.
if (allowed && allowed.length > 0 && !allowed.includes(s.destination)) {
return {
id,
summary: `${s.name} contacts ${s.destination}, which is not in the declared set`,
determination: 'fail',
severity: 'critical',
detail: 'An egress allowlist exists because a deploy reaching an unexpected host is either a supply-chain problem or a leak. Volume is irrelevant here.',
evidence: [stepEvidence(s)],
}
}
if (s.bytes === null) {
return {
id,
summary: `${s.name} moves an unknown volume to ${s.destination}`,
determination: 'not-assessed',
severity: 'high',
detail: 'An unmeasured transfer is not a small one. It cannot be counted against the budget, so the budget below is a lower bound, not a total.',
evidence: [stepEvidence(s)],
}
}
const rate = peakRate(s)
if (rate !== null && budget.maxBytesPerSecond && rate * (budget.concurrency ?? 1) > budget.maxBytesPerSecond) {
return {
id,
summary: `${s.name} peaks at ${fmt(rate * (budget.concurrency ?? 1))}/s`,
determination: 'fail',
severity: 'high',
detail: `Above the ${fmt(budget.maxBytesPerSecond)}/s ceiling${(budget.concurrency ?? 1) > 1 ? ` at concurrency ${budget.concurrency}` : ''}. The same bytes spread over a longer window would pass — the total is not the problem, the shape is.`,
evidence: [stepEvidence(s)],
}
}
if (rate === null && budget.maxBytesPerSecond) {
return {
id,
summary: `${s.name} has no duration, so its peak rate cannot be checked`,
determination: 'not-assessed',
severity: 'medium',
detail: 'A rate ceiling is declared and this step cannot be tested against it.',
evidence: [stepEvidence(s)],
}
}
return {
id,
summary: `${s.name} — ${fmt(worstCaseBytes(s)!)} to ${s.destination}`,
determination: 'pass',
severity: 'info',
evidence: [stepEvidence(s)],
}
}
/**
* The total, computed over WORST-CASE bytes.
*
* Reported as its own finding, and reported as a lower bound when any step's
* volume is unknown — a total assembled from partial measurements presented
* as a total is the way a budget check reassures without checking.
*/
function totalFinding(steps: DeployStep[], budget: SignatureBudget): Finding | null {
if (!budget.maxTotalBytes) return null
const known = steps.filter(s => s.bytes !== null)
const unknown = steps.length - known.length
const total = known.reduce((n, s) => n + worstCaseBytes(s)!, 0)
const over = total > budget.maxTotalBytes
if (unknown > 0 && !over) {
return {
id: 'total',
summary: `${fmt(total)} of ${fmt(budget.maxTotalBytes)} accounted for, with ${unknown} step(s) unmeasured`,
determination: 'not-assessed',
severity: 'high',
detail: 'This is a lower bound, not a total. The unmeasured steps could put it over, and a partial sum presented as a total is how a budget check reassures without checking.',
evidence: [evidence.measurement('worst-case egress', total, known.length, { unit: ' B' })],
}
}
return {
id: 'total',
summary: over
? `${fmt(total)} exceeds the ${fmt(budget.maxTotalBytes)} budget`
: `${fmt(total)} within the ${fmt(budget.maxTotalBytes)} budget`,
determination: over ? 'fail' : 'pass',
severity: over ? 'critical' : 'info',
detail: over
? 'Computed over worst-case bytes: every retry counts. A step budgeted at one attempt is budgeted at its best case.'
: undefined,
evidence: [evidence.measurement('worst-case egress', total, known.length, { unit: ' B' })],
}
}
/** Check a deployment plan against a signature budget. */
export function checkPlan(steps: DeployStep[], budget: SignatureBudget = {}): CapabilityReport {
const list = steps ?? []
if (list.length === 0) {
return {
capability: 'QuietDeploy',
scope: 'no steps described',
examined: 0,
findings: [],
notes: ['No deploy steps were described, so no signature was estimated. An unenumerated step still moves bytes.'],
}
}
const total = totalFinding(list, budget)
const destinations = [...new Set(list.map(s => s.destination))].sort()
return {
capability: 'QuietDeploy',
scope: `${list.length} step(s) across ${destinations.length} destination(s)`,
examined: list.length,
findings: [...(total ? [total] : []), ...list.map(s => stepFinding(s, budget))],
notes: [
`destinations: ${destinations.join(', ')}`,
...(budget.allowedDestinations?.length
? []
: ['No destination allowlist was supplied, so no step could be checked against one.']),
],
}
}
/** Render a signature check for a terminal, CI log or review. */
export function formatPlan(
steps: DeployStep[],
budget: SignatureBudget = {},
opts: FormatOptions = {},
): string {
return renderReport(checkPlan(steps, budget), opts)
}
export { fmt as formatBytes }
+125
View File
@@ -0,0 +1,125 @@
import { describe, expect, it } from 'vitest'
import { overall, validateReport } from '@extant2000/evidence-record'
import {
checkPlan,
formatPlan,
peakRate,
worstCaseBytes,
type DeployStep,
type SignatureBudget,
} from '../src/index.js'
const step = (p: Partial<DeployStep> = {}): DeployStep => ({
name: 'pull-base-image',
destination: 'registry.gitlab.com',
bytes: 200_000_000,
durationSeconds: 60,
where: '.gitlab-ci.yml',
...p,
})
describe('retries are cost, not a footnote', () => {
it('counts every attempt in the worst case', () => {
// A step budgeted at one attempt is budgeted at its best case.
expect(worstCaseBytes(step({ bytes: 100, retries: 3 }))).toBe(300)
expect(worstCaseBytes(step({ bytes: 100 }))).toBe(100)
})
it('a plan that fits on first attempt and not with retries fails', () => {
const budget: SignatureBudget = { maxTotalBytes: 250_000_000 }
expect(overall(checkPlan([step({ retries: 1 })], budget))).toBe('pass')
const r = checkPlan([step({ retries: 2 })], budget)
expect(r.findings.find(f => f.id === 'total')!.determination).toBe('fail')
expect(r.findings.find(f => f.id === 'total')!.detail).toContain('every retry counts')
})
})
describe('an unexpected destination is a different kind of problem', () => {
const budget: SignatureBudget = { allowedDestinations: ['registry.gitlab.com'] }
it('fails a step reaching outside the declared set', () => {
const r = checkPlan([step({ name: 'fetch-tool', destination: 'cdn.example.net', bytes: 1024 })], budget)
expect(r.findings.find(f => f.id === 'fetch-tool')!.determination).toBe('fail')
expect(r.findings.find(f => f.id === 'fetch-tool')!.severity).toBe('critical')
})
it('stays critical however small the transfer', () => {
// Volume is irrelevant: an unexpected host is supply chain or leak.
const r = checkPlan([step({ name: 'ping', destination: 'evil.example', bytes: 1 })], budget)
expect(r.findings.find(f => f.id === 'ping')!.severity).toBe('critical')
expect(formatPlan([step({ name: 'ping', destination: 'evil.example', bytes: 1 })], budget))
.toContain('Volume is irrelevant here')
})
it('says so when no allowlist was supplied', () => {
expect(formatPlan([step()], {})).toContain('no step could be checked against one')
})
it('passes a step inside the declared set', () => {
expect(overall(checkPlan([step()], budget))).toBe('pass')
})
})
describe('shape, not just total', () => {
it('fails a burst that fits the total budget', () => {
// 200 MB over 60s = 3.3 MB/s. The same bytes over an hour would pass.
const r = checkPlan([step()], { maxTotalBytes: 1e9, maxBytesPerSecond: 1_000_000 })
const f = r.findings.find(x => x.id === 'pull-base-image')!
expect(f.determination).toBe('fail')
expect(f.detail).toContain('the total is not the problem, the shape is')
})
it('multiplies the peak by concurrency', () => {
const budget: SignatureBudget = { maxBytesPerSecond: 5_000_000, concurrency: 4 }
// 3.3 MB/s alone passes; x4 concurrent does not.
expect(overall(checkPlan([step()], { maxBytesPerSecond: 5_000_000 }))).toBe('pass')
expect(overall(checkPlan([step()], budget))).toBe('fail')
})
it('cannot check a rate without a duration, and says so', () => {
const r = checkPlan([step({ durationSeconds: undefined })], { maxBytesPerSecond: 1_000_000 })
expect(r.findings.find(f => f.id === 'pull-base-image')!.determination).toBe('not-assessed')
expect(peakRate(step({ durationSeconds: undefined }))).toBeNull()
})
})
describe('an unmeasured transfer is not a small one', () => {
it('reports an unknown volume as not-assessed, never zero', () => {
const r = checkPlan([step({ bytes: null })], { maxTotalBytes: 1e9 })
const f = r.findings.find(x => x.id === 'pull-base-image')!
expect(f.determination).toBe('not-assessed')
expect(f.detail).toContain('An unmeasured transfer is not a small one')
})
it('reports the total as a LOWER BOUND when any step is unmeasured', () => {
// A partial sum presented as a total is how a budget check reassures
// without checking.
const r = checkPlan([step({ bytes: 1000 }), step({ name: 'unknown-pull', bytes: null })],
{ maxTotalBytes: 1e9 })
const total = r.findings.find(f => f.id === 'total')!
expect(total.determination).toBe('not-assessed')
expect(total.detail).toContain('lower bound, not a total')
})
it('still fails when the KNOWN bytes alone exceed the budget', () => {
// Unmeasured steps cannot rescue a plan that is already over.
const r = checkPlan([step({ bytes: 2e9 }), step({ name: 'x', bytes: null })], { maxTotalBytes: 1e9 })
expect(r.findings.find(f => f.id === 'total')!.determination).toBe('fail')
})
})
describe('conformance with the evidence-record standard', () => {
it('an empty plan is not-assessed, and says what empty means', () => {
expect(overall(checkPlan([]))).toBe('not-assessed')
expect(formatPlan([])).toContain('An unenumerated step still moves bytes')
})
it('every conclusion carries a citation', () => {
expect(validateReport(checkPlan([step(), step({ name: 'b', destination: 'x', bytes: 5 })],
{ maxTotalBytes: 1e9, allowedDestinations: ['registry.gitlab.com'] }))).toEqual([])
})
it('cites the file each step is defined in', () => {
expect(formatPlan([step()], {}, { evidence: 'full' })).toContain('.gitlab-ci.yml')
})
})
+9
View File
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "dist-cjs",
"declaration": false
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"target": "ES2022", "module": "ES2022", "moduleResolution": "bundler",
"declaration": true, "outDir": "dist", "rootDir": "src",
"strict": true, "skipLibCheck": true
},
"include": ["src/**/*.ts"]
}