@clear-capabilities/agentic-security-scanner 0.161.0 → 0.163.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/bin/agentic-security.js +98 -2
- package/dist/1340.index.js +1871 -0
- package/dist/3477.index.js +727 -0
- package/dist/3499.index.js +23 -3
- package/dist/4113.index.js +59 -8
- package/dist/5014.index.js +833 -0
- package/dist/5756.index.js +2 -2
- package/dist/6257.index.js +1 -1
- package/dist/6907.index.js +248 -0
- package/dist/6994.index.js +1 -1
- package/dist/7033.index.js +33 -5
- package/dist/7439.index.js +1822 -0
- package/dist/7838.index.js +38 -2
- package/dist/8798.index.js +1 -1
- package/dist/9207.index.js +5 -0
- package/dist/9560.index.js +2336 -27
- package/dist/957.index.js +1 -1
- package/dist/{1905.index.js → 9999.index.js} +306 -13
- package/dist/agentic-security.mjs +12 -12
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/package.json +39 -7
- package/src/capabilities/CLAUDE.md +114 -0
- package/src/capabilities/address.js +73 -0
- package/src/capabilities/attack-coverage.js +93 -0
- package/src/capabilities/decide.js +256 -0
- package/src/capabilities/delegate.js +69 -0
- package/src/capabilities/egress.js +20 -0
- package/src/capabilities/hook-advice.js +50 -0
- package/src/capabilities/index.js +32 -0
- package/src/capabilities/manifest.js +344 -0
- package/src/capabilities/outbound.js +189 -0
- package/src/capabilities/paths.js +57 -0
- package/src/capabilities/probes.js +211 -0
- package/src/capabilities/proxy.js +182 -0
- package/src/capabilities/reasons.js +67 -0
- package/src/capabilities/receipts.js +356 -0
- package/src/capabilities/records.js +58 -0
- package/src/capabilities/recovery.js +367 -0
- package/src/capabilities/report.js +81 -0
- package/src/capabilities/runner.js +236 -0
- package/src/capabilities/secrets.js +26 -0
- package/src/capabilities/tool-gate.js +119 -0
- package/src/capabilities/tool-registry.js +60 -0
- package/src/dataflow/CLAUDE.md +29 -0
- package/src/dataflow/catalog.js +21 -0
- package/src/dataflow/engine.js +20 -0
- package/src/dataflow/guard-dominance.js +352 -0
- package/src/discovery/CLAUDE.md +18 -0
- package/src/discovery/index.js +43 -1
- package/src/discovery/lenses.js +18 -0
- package/src/discovery/memory.js +7 -5
- package/src/engine.js +80 -15
- package/src/fix/apply-fix-service.js +33 -3
- package/src/integrations/index.js +5 -2
- package/src/ir/CLAUDE.md +14 -0
- package/src/ir/implicit-handler-params.js +74 -0
- package/src/ir/parser-cs.js +20 -0
- package/src/ir/parser-go.js +30 -13
- package/src/ir/parser-java.js +11 -0
- package/src/language/nix-eval-isolation.js +33 -5
- package/src/lineage/CLAUDE.md +31 -0
- package/src/lineage/deployment/adapter-cloud.js +202 -0
- package/src/lineage/deployment/adapter-compose.js +90 -0
- package/src/lineage/deployment/adapter-kit.js +142 -0
- package/src/lineage/deployment/adapter-kubernetes.js +247 -0
- package/src/lineage/deployment/attack-paths.js +443 -0
- package/src/lineage/deployment/boundaries-run.js +223 -0
- package/src/lineage/deployment/boundary-graph.js +567 -0
- package/src/lineage/deployment/cross-repo.js +253 -0
- package/src/lineage/deployment/drift.js +383 -0
- package/src/lineage/deployment/ingest.js +221 -0
- package/src/lineage/deployment/projection.js +244 -0
- package/src/lineage/deployment/trace-correlation.js +541 -0
- package/src/lineage/source-registry.js +19 -0
- package/src/mcp/CLAUDE.md +14 -3
- package/src/mcp/invariant-tools.js +64 -0
- package/src/mcp/portfolio-tools.js +79 -0
- package/src/mcp/redact.js +15 -0
- package/src/mcp/server.js +24 -3
- package/src/mcp/tools.js +30 -5
- package/src/posture/CLAUDE.md +505 -0
- package/src/posture/accuracy-scorecard.js +95 -4
- package/src/posture/assurance/baseline-inventory.js +218 -0
- package/src/posture/assurance/baseline.js +322 -0
- package/src/posture/assurance/bounded-io.js +145 -0
- package/src/posture/assurance/config.js +299 -0
- package/src/posture/assurance/contracts.js +315 -0
- package/src/posture/assurance/identity.js +62 -0
- package/src/posture/assurance/migrations.js +259 -0
- package/src/posture/assurance/rollback.js +214 -0
- package/src/posture/assurance/rollout.js +200 -0
- package/src/posture/assurance/schema-kit.js +111 -0
- package/src/posture/assurance/verification-record.js +258 -0
- package/src/posture/attestation.js +5 -0
- package/src/posture/autopilot.js +28 -1
- package/src/posture/business-logic.js +26 -4
- package/src/posture/evaluation/bakeoff.js +148 -0
- package/src/posture/evaluation/custody.js +200 -0
- package/src/posture/evaluation/deployment-ablation.js +416 -0
- package/src/posture/evaluation/dev-cases.js +65 -0
- package/src/posture/evaluation/economics.js +85 -0
- package/src/posture/evaluation/gates.js +161 -0
- package/src/posture/evaluation/grouping.js +101 -0
- package/src/posture/evaluation/interval.js +132 -0
- package/src/posture/evaluation/invariant-ablation.js +325 -0
- package/src/posture/evaluation/labels.js +200 -0
- package/src/posture/evaluation/protocol.js +308 -0
- package/src/posture/evaluation/release-gate.js +209 -0
- package/src/posture/evaluation/report.js +158 -0
- package/src/posture/evaluation/runner.js +273 -0
- package/src/posture/evaluation/scan-child.js +80 -0
- package/src/posture/evaluation/score.js +174 -0
- package/src/posture/evaluation/synthetic.js +90 -0
- package/src/posture/evaluation/why-missed.js +219 -0
- package/src/posture/evidence-bundle.js +93 -7
- package/src/posture/execution-proof.js +11 -1
- package/src/posture/fix-verify-loop.js +20 -6
- package/src/posture/fix-verify.js +37 -2
- package/src/posture/fleet.js +11 -2
- package/src/posture/invariants/cli.js +95 -0
- package/src/posture/invariants/coverage.js +164 -0
- package/src/posture/invariants/export.js +178 -0
- package/src/posture/invariants/expressions.js +46 -0
- package/src/posture/invariants/lifecycle.js +289 -0
- package/src/posture/invariants/project-input.js +55 -0
- package/src/posture/invariants/repair.js +340 -0
- package/src/posture/invariants/run.js +45 -0
- package/src/posture/invariants/scenarios.js +311 -0
- package/src/posture/invariants/schema.js +167 -0
- package/src/posture/invariants/shrink.js +407 -0
- package/src/posture/invariants/state-assertions.js +165 -0
- package/src/posture/logic-claims.js +12 -0
- package/src/posture/model-routing.js +40 -0
- package/src/posture/oracles/adapters.js +531 -0
- package/src/posture/oracles/conformance.js +276 -0
- package/src/posture/oracles/oracle.js +453 -0
- package/src/posture/oracles/registry.js +76 -0
- package/src/posture/oracles/scenario-classes.js +223 -0
- package/src/posture/portfolio/backend.js +279 -0
- package/src/posture/portfolio/bundle.js +314 -0
- package/src/posture/portfolio/cli.js +142 -0
- package/src/posture/portfolio/manifest.js +263 -0
- package/src/posture/portfolio/progress.js +267 -0
- package/src/posture/portfolio/resume.js +130 -0
- package/src/posture/portfolio/retention.js +207 -0
- package/src/posture/portfolio/scheduler.js +488 -0
- package/src/posture/portfolio/signing.js +155 -0
- package/src/posture/portfolio/wording.js +59 -0
- package/src/posture/portfolio/work-units.js +405 -0
- package/src/posture/replay/replay.js +250 -0
- package/src/posture/routing/adapter.js +140 -0
- package/src/posture/routing/calibration.js +278 -0
- package/src/posture/routing/canary.js +141 -0
- package/src/posture/routing/control.js +35 -0
- package/src/posture/routing/decide.js +211 -0
- package/src/posture/routing/drift.js +137 -0
- package/src/posture/routing/economics.js +185 -0
- package/src/posture/routing/feedback.js +207 -0
- package/src/posture/routing/index.js +31 -0
- package/src/posture/routing/outcomes.js +281 -0
- package/src/posture/routing/promotion.js +291 -0
- package/src/posture/routing/receipts.js +59 -0
- package/src/posture/routing/report.js +142 -0
- package/src/posture/routing/shadow.js +53 -0
- package/src/posture/specification-mining.js +26 -0
- package/src/posture/verification/advisory-state.js +71 -0
- package/src/posture/verification/emit.js +257 -0
- package/src/posture/verification/hypothesis-promotion.js +211 -0
- package/src/posture/verification/patch-negative.js +226 -0
- package/src/posture/verification/patch-promotion.js +113 -0
- package/src/posture/verification/projection.js +183 -0
- package/src/posture/verification/repair-records.js +124 -0
- package/src/posture/verifier.js +16 -0
- package/src/report/index.js +100 -1
- package/src/sandbox/CLAUDE.md +51 -0
- package/src/sandbox/backend-namespace.js +7 -0
- package/src/sandbox/backend-userspace.js +151 -34
- package/src/sandbox/control-probes.js +215 -0
- package/src/sandbox/supervise.js +201 -0
- package/src/sandbox/trust-boundary.js +113 -0
- package/src/sandbox/trust-domains.js +171 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// Trust domains for verification (CORE-003).
|
|
2
|
+
//
|
|
3
|
+
// Four domains stay separate, and this module is the single place that says
|
|
4
|
+
// which one may do what. It is deliberately data plus small pure functions: the
|
|
5
|
+
// ENFORCEMENT lives at the process boundary (`trust-boundary.js`, the sandbox
|
|
6
|
+
// profile, file modes), not here. A table nobody consults at the boundary would
|
|
7
|
+
// be documentation pretending to be a control, so every entry below has an
|
|
8
|
+
// attack test that tries the forbidden action through the real boundary.
|
|
9
|
+
//
|
|
10
|
+
// target analyzed code and anything it spawns. Adversarial by assumption.
|
|
11
|
+
// worker the model/agent that proposes hypotheses, scenarios and patches.
|
|
12
|
+
// Adversarial for authority purposes: may be prompt-injected by the
|
|
13
|
+
// target. Authors proposals, never truth.
|
|
14
|
+
// verifier the protected verifier / evaluation custodian. Holds sealed labels,
|
|
15
|
+
// runs oracles, writes authoritative evidence.
|
|
16
|
+
// signer holds signing key material and issues signatures over evidence the
|
|
17
|
+
// verifier produced. Never executes target or worker code.
|
|
18
|
+
//
|
|
19
|
+
// What a lower-trust domain may NEVER do, whatever it prints or writes:
|
|
20
|
+
// - read signing keys, the install HMAC key or sealed labels
|
|
21
|
+
// - write authoritative evidence
|
|
22
|
+
// - set a verification status (only verifier-observed evidence can)
|
|
23
|
+
// - read host paths unrelated to its own workspace (credential directories)
|
|
24
|
+
import os from 'node:os';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
|
|
27
|
+
export const DOMAINS = Object.freeze({
|
|
28
|
+
TARGET: 'target',
|
|
29
|
+
WORKER: 'worker',
|
|
30
|
+
VERIFIER: 'verifier',
|
|
31
|
+
SIGNER: 'signer',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const RESOURCES = Object.freeze({
|
|
35
|
+
SIGNING_KEY: 'signing-key',
|
|
36
|
+
HMAC_KEY: 'hmac-key',
|
|
37
|
+
SEALED_LABELS: 'sealed-labels',
|
|
38
|
+
AUTHORITATIVE_EVIDENCE: 'authoritative-evidence',
|
|
39
|
+
VERIFICATION_STATUS: 'verification-status',
|
|
40
|
+
HOST_CREDENTIALS: 'host-credentials',
|
|
41
|
+
WORKSPACE: 'workspace',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// domain -> resource -> allowed actions. Absence means DENIED (default deny).
|
|
45
|
+
const POLICY = Object.freeze({
|
|
46
|
+
[DOMAINS.TARGET]: { [RESOURCES.WORKSPACE]: ['read', 'write'] },
|
|
47
|
+
[DOMAINS.WORKER]: { [RESOURCES.WORKSPACE]: ['read', 'write'] },
|
|
48
|
+
[DOMAINS.VERIFIER]: {
|
|
49
|
+
[RESOURCES.WORKSPACE]: ['read'],
|
|
50
|
+
[RESOURCES.SEALED_LABELS]: ['read'],
|
|
51
|
+
[RESOURCES.AUTHORITATIVE_EVIDENCE]: ['read', 'write'],
|
|
52
|
+
[RESOURCES.VERIFICATION_STATUS]: ['write'],
|
|
53
|
+
[RESOURCES.HMAC_KEY]: ['read'],
|
|
54
|
+
},
|
|
55
|
+
[DOMAINS.SIGNER]: {
|
|
56
|
+
[RESOURCES.SIGNING_KEY]: ['read'],
|
|
57
|
+
[RESOURCES.AUTHORITATIVE_EVIDENCE]: ['read'],
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** Default-deny policy lookup. */
|
|
62
|
+
export function mayDo(domain, resource, action) {
|
|
63
|
+
return !!POLICY[domain]?.[resource]?.includes(action);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Domains that execute or are influenced by untrusted content. */
|
|
67
|
+
export function isUntrusted(domain) {
|
|
68
|
+
return domain === DOMAINS.TARGET || domain === DOMAINS.WORKER;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---- protected host paths --------------------------------------------------
|
|
72
|
+
|
|
73
|
+
/** Config directory holding the Ed25519 keys and the install HMAC key. */
|
|
74
|
+
export function keyDirectory(env = process.env) {
|
|
75
|
+
const xdg = env.XDG_CONFIG_HOME;
|
|
76
|
+
const base = xdg && xdg.length ? xdg : path.join(os.homedir(), '.config');
|
|
77
|
+
return path.join(base, 'agentic-security');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Credential locations under the user's home that no target has a reason to
|
|
81
|
+
// read. A denylist can never be complete, so it is the floor, not the claim:
|
|
82
|
+
// the caller adds sealed-label and evidence directories explicitly.
|
|
83
|
+
const HOME_CREDENTIAL_PATHS = Object.freeze([
|
|
84
|
+
'.ssh', '.aws', '.gnupg', '.azure', '.kube', '.docker', '.netrc', '.npmrc',
|
|
85
|
+
'.pypirc', '.git-credentials', '.claude', '.config/gcloud', '.config/gh',
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Every host path a target process must not read. The signing/HMAC key
|
|
90
|
+
* directory is always included.
|
|
91
|
+
*/
|
|
92
|
+
export function protectedReadPaths({
|
|
93
|
+
home = os.homedir(), env = process.env, labelDirs = [], evidenceDirs = [], extra = [],
|
|
94
|
+
} = {}) {
|
|
95
|
+
const out = [keyDirectory(env)];
|
|
96
|
+
for (const rel of HOME_CREDENTIAL_PATHS) out.push(path.join(home, rel));
|
|
97
|
+
for (const p of [...labelDirs, ...evidenceDirs, ...extra]) if (p) out.push(path.resolve(p));
|
|
98
|
+
return [...new Set(out)];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---- secret material in worker environments --------------------------------
|
|
102
|
+
|
|
103
|
+
const SECRET_NAME = /(?:^|_)(?:secret|token|password|passwd|api_?key|private_?key|credential|hmac|signing|auth)(?:_|$)|^(?:AWS_|GITHUB_|NPM_|ANTHROPIC_|OPENAI_)/i;
|
|
104
|
+
const PEM_PRIVATE = /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
|
|
105
|
+
// An explicit allowlist wins over the name heuristic: these carry no secret.
|
|
106
|
+
const SAFE_NAMES = new Set(['PATH', 'HOME', 'TMPDIR', 'LANG', 'ROOT', 'LC_ALL', 'TZ', 'CI']);
|
|
107
|
+
|
|
108
|
+
/** Names (never values) of environment entries that look like secret material. */
|
|
109
|
+
export function secretEnvNames(env = {}) {
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const [k, v] of Object.entries(env || {})) {
|
|
112
|
+
if (SAFE_NAMES.has(k)) continue;
|
|
113
|
+
if (SECRET_NAME.test(k) || PEM_PRIVATE.test(String(v ?? ''))) out.push(k);
|
|
114
|
+
}
|
|
115
|
+
return out.sort();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** `{ ok:false, offenders }` when an environment bound for a worker holds secrets. */
|
|
119
|
+
export function assertNoSecretMaterial(env = {}) {
|
|
120
|
+
const offenders = secretEnvNames(env);
|
|
121
|
+
return { ok: offenders.length === 0, offenders };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Copy of `env` without secret-looking entries. */
|
|
125
|
+
export function scrubEnv(env = {}) {
|
|
126
|
+
const drop = new Set(secretEnvNames(env));
|
|
127
|
+
return Object.fromEntries(Object.entries(env || {}).filter(([k]) => !drop.has(k)));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---- verification status ---------------------------------------------------
|
|
131
|
+
|
|
132
|
+
// Mirrors the PRD state model. Only this module decides how a status is formed
|
|
133
|
+
// from a boundary run, and it never reads target output.
|
|
134
|
+
export const VERIFICATION_STATUSES = Object.freeze(
|
|
135
|
+
['not-run', 'unsupported', 'inconclusive', 'error', 'refuted', 'confirmed'],
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Status from what the BOUNDARY observed (did it run, did it error). A run on
|
|
140
|
+
* its own can never confirm anything: that takes verifier-observed evidence
|
|
141
|
+
* (`settleVerification`).
|
|
142
|
+
*/
|
|
143
|
+
export function classifyRun(run) {
|
|
144
|
+
if (!run || run.executed !== true) return 'not-run';
|
|
145
|
+
if (run.status === 'error') return 'error';
|
|
146
|
+
return 'inconclusive';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Settle a verification status. `evidence` must come from verifier-domain code
|
|
151
|
+
* (`observedBy: 'verifier'`) that examined state the target cannot write (for
|
|
152
|
+
* example by re-running the oracle outside the target's reach). Target stdout,
|
|
153
|
+
* stderr and workspace files are NOT evidence. `confirmed` is only reachable
|
|
154
|
+
* from an executed run plus satisfied verifier evidence; `refuted` needs the
|
|
155
|
+
* oracle to declare its preconditions held.
|
|
156
|
+
*/
|
|
157
|
+
export function settleVerification(run, evidence) {
|
|
158
|
+
const base = classifyRun(run);
|
|
159
|
+
if (base !== 'inconclusive') return base;
|
|
160
|
+
if (!evidence || evidence.observedBy !== DOMAINS.VERIFIER) return base;
|
|
161
|
+
if (evidence.satisfied === true) return 'confirmed';
|
|
162
|
+
if (evidence.satisfied === false && evidence.preconditionsHeld === true) return 'refuted';
|
|
163
|
+
return base;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const STATUS_LIKE = /\b(?:verified|confirmed|execution-proven|status\s*[:=])\b/i;
|
|
167
|
+
|
|
168
|
+
/** Count of target-output lines that merely LOOK like a status claim (informational). */
|
|
169
|
+
export function countStatusLikeLines(text) {
|
|
170
|
+
return String(text || '').split('\n').filter((l) => STATUS_LIKE.test(l)).length;
|
|
171
|
+
}
|