@red-codes/policy 1.0.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.
@@ -0,0 +1,169 @@
1
+ // Policy pack loader — resolves, loads, validates, and merges policy packs.
2
+ // Supports local directory packs and npm-style package references.
3
+ // Includes version compatibility checking for policy packs.
4
+ //
5
+ // A policy pack is a YAML or JSON policy file that can be referenced via the
6
+ // `extends` key in a policy definition. Packs are loaded and their rules are
7
+ // merged with the local policy, with local rules taking precedence.
8
+ import { readFileSync, existsSync } from 'node:fs';
9
+ import { resolve, join } from 'node:path';
10
+ import { loadYamlPolicy } from './yaml-loader.js';
11
+ import { validatePolicy } from './loader.js';
12
+ import { parsePackReference, checkCompatibility, satisfiesRange } from './pack-version.js';
13
+ /** Candidate filenames when resolving a pack directory */
14
+ const PACK_MANIFEST_CANDIDATES = [
15
+ 'agentguard-pack.yaml',
16
+ 'agentguard-pack.yml',
17
+ 'agentguard-pack.json',
18
+ 'agentguard.yaml',
19
+ 'agentguard.yml',
20
+ ];
21
+ /**
22
+ * Resolve a single pack reference to an absolute file path.
23
+ *
24
+ * Supports three reference styles:
25
+ * 1. Relative path — `"./packs/strict"` or `"./packs/strict.yaml"`
26
+ * 2. Absolute path — `"/home/user/packs/strict.yaml"`
27
+ * 3. npm package — `"@agentguard/security-pack"` resolved from node_modules
28
+ *
29
+ * References may include a version constraint suffix (e.g., `"./pack@^1.2.0"`),
30
+ * which is stripped before path resolution.
31
+ */
32
+ export function resolvePackPath(ref, baseDir) {
33
+ // 1. Direct file reference (relative or absolute)
34
+ const directPath = resolve(baseDir, ref);
35
+ if (existsSync(directPath)) {
36
+ // If it's a file, use it directly
37
+ if (directPath.endsWith('.yaml') ||
38
+ directPath.endsWith('.yml') ||
39
+ directPath.endsWith('.json')) {
40
+ return directPath;
41
+ }
42
+ // If it's a directory, look for manifest files
43
+ for (const candidate of PACK_MANIFEST_CANDIDATES) {
44
+ const candidatePath = join(directPath, candidate);
45
+ if (existsSync(candidatePath)) {
46
+ return candidatePath;
47
+ }
48
+ }
49
+ }
50
+ // Try with common extensions if the direct path didn't work
51
+ for (const ext of ['.yaml', '.yml', '.json']) {
52
+ const withExt = directPath + ext;
53
+ if (existsSync(withExt)) {
54
+ return withExt;
55
+ }
56
+ }
57
+ // 2. npm package reference — search node_modules
58
+ const nodeModulesPath = join(baseDir, 'node_modules', ref);
59
+ if (existsSync(nodeModulesPath)) {
60
+ for (const candidate of PACK_MANIFEST_CANDIDATES) {
61
+ const candidatePath = join(nodeModulesPath, candidate);
62
+ if (existsSync(candidatePath)) {
63
+ return candidatePath;
64
+ }
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ /**
70
+ * Load a single policy pack from a resolved file path.
71
+ */
72
+ export function loadPackFile(filePath) {
73
+ const content = readFileSync(filePath, 'utf8');
74
+ if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
75
+ return loadYamlPolicy(content, `pack:${filePath}`);
76
+ }
77
+ try {
78
+ const parsed = JSON.parse(content);
79
+ const result = validatePolicy(parsed);
80
+ if (!result.valid) {
81
+ return null;
82
+ }
83
+ return {
84
+ id: parsed.id || `pack:${filePath}`,
85
+ name: parsed.name || 'JSON Pack',
86
+ description: parsed.description,
87
+ rules: parsed.rules,
88
+ severity: parsed.severity ?? 3,
89
+ version: parsed.version,
90
+ agentguardVersion: parsed.agentguardVersion,
91
+ };
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Resolve and load all policy packs from an `extends` list.
99
+ *
100
+ * @param extends_ - Array of pack references (paths, npm package names, or versioned refs like "pack@^1.0.0")
101
+ * @param baseDir - Directory to resolve relative paths from
102
+ * @param options - Optional settings including the current AgentGuard version for compatibility checks
103
+ * @returns Loaded pack policies, errors, and version warnings
104
+ */
105
+ export function resolveExtends(extends_, baseDir, options) {
106
+ const policies = [];
107
+ const errors = [];
108
+ const warnings = [];
109
+ const seenIds = new Set();
110
+ for (const rawRef of extends_) {
111
+ const { ref, versionConstraint } = parsePackReference(rawRef);
112
+ const resolvedPath = resolvePackPath(ref, baseDir);
113
+ if (!resolvedPath) {
114
+ errors.push(`Pack not found: "${ref}" (searched from ${baseDir})`);
115
+ continue;
116
+ }
117
+ const pack = loadPackFile(resolvedPath);
118
+ if (!pack) {
119
+ errors.push(`Failed to load pack: "${ref}" (${resolvedPath})`);
120
+ continue;
121
+ }
122
+ if (seenIds.has(pack.id)) {
123
+ errors.push(`Duplicate pack ID: "${pack.id}" from "${ref}"`);
124
+ continue;
125
+ }
126
+ // Check version pin constraint (from extends reference like "pack@^1.2.0")
127
+ if (versionConstraint) {
128
+ if (pack.version) {
129
+ if (!satisfiesRange(pack.version, versionConstraint)) {
130
+ warnings.push(`Pack "${pack.id}" version ${pack.version} does not satisfy ` +
131
+ `pinned constraint ${versionConstraint} (from "${rawRef}")`);
132
+ }
133
+ }
134
+ else {
135
+ warnings.push(`Pack "${pack.id}" has no version field but version pin ` +
136
+ `${versionConstraint} was requested (from "${rawRef}")`);
137
+ }
138
+ }
139
+ // Check AgentGuard version compatibility
140
+ if (pack.agentguardVersion && options?.currentAgentguardVersion) {
141
+ const compat = checkCompatibility(pack.agentguardVersion, options.currentAgentguardVersion);
142
+ if (!compat.compatible) {
143
+ errors.push(`Pack "${pack.id}" is incompatible: ${compat.reason}`);
144
+ continue;
145
+ }
146
+ }
147
+ seenIds.add(pack.id);
148
+ policies.push(pack);
149
+ }
150
+ return { policies, errors, warnings };
151
+ }
152
+ /**
153
+ * Merge pack policies with a local policy.
154
+ *
155
+ * Precedence: local rules override pack rules. Within packs, earlier entries
156
+ * in the `extends` list take precedence over later entries.
157
+ *
158
+ * The merge strategy is:
159
+ * 1. Collect all rules from packs (in extends order)
160
+ * 2. Append local rules (which take precedence during evaluation since
161
+ * the evaluator checks deny rules first, then allow rules)
162
+ * 3. Return a single merged policy array
163
+ */
164
+ export function mergePolicies(localPolicy, packPolicies) {
165
+ // Pack policies come first (lower precedence in evaluation order)
166
+ // Local policy comes last (highest precedence)
167
+ return [...packPolicies, localPolicy];
168
+ }
169
+ //# sourceMappingURL=pack-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-loader.js","sourceRoot":"","sources":["../src/pack-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ export interface SemVer {
2
+ major: number;
3
+ minor: number;
4
+ patch: number;
5
+ }
6
+ export interface CompatibilityResult {
7
+ compatible: boolean;
8
+ reason?: string;
9
+ }
10
+ export interface ParsedPackReference {
11
+ ref: string;
12
+ versionConstraint?: string;
13
+ }
14
+ /**
15
+ * Parse a semver string into its components.
16
+ * Returns null if the string is not a valid semver.
17
+ */
18
+ export declare function parseSemver(version: string): SemVer | null;
19
+ /**
20
+ * Compare two semver versions.
21
+ * Returns -1 if a < b, 0 if a === b, 1 if a > b.
22
+ */
23
+ export declare function compareSemver(a: SemVer, b: SemVer): -1 | 0 | 1;
24
+ /**
25
+ * Check if a version satisfies a version range.
26
+ *
27
+ * Supported range formats:
28
+ * - Exact: `"1.2.3"` — must match exactly
29
+ * - Greater-or-equal: `">=1.2.3"` — version must be >= range
30
+ * - Caret: `"^1.2.3"` — compatible with (same major, >= minor.patch)
31
+ * - Tilde: `"~1.2.3"` — reasonably close (same major.minor, >= patch)
32
+ */
33
+ export declare function satisfiesRange(version: string, range: string): boolean;
34
+ /**
35
+ * Check if a policy pack is compatible with the current AgentGuard version.
36
+ *
37
+ * @param packAgentguardVersion — the `agentguardVersion` range from the pack (e.g., ">=2.0.0")
38
+ * @param currentVersion — the running AgentGuard version (e.g., "2.2.0")
39
+ */
40
+ export declare function checkCompatibility(packAgentguardVersion: string, currentVersion: string): CompatibilityResult;
41
+ /**
42
+ * Parse a pack reference that may include a version constraint.
43
+ *
44
+ * Supports `"pack-name@^1.2.0"` syntax where the `@version` suffix
45
+ * specifies a version pin for the pack's own version.
46
+ *
47
+ * Scoped npm packages (e.g., `@agentguard/security-pack@^1.0.0`) are
48
+ * handled by splitting on the last `@`.
49
+ */
50
+ export declare function parsePackReference(ref: string): ParsedPackReference;
51
+ //# sourceMappingURL=pack-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-version.d.ts","sourceRoot":"","sources":["../src/pack-version.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAID;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAK9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAoCtE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,qBAAqB,EAAE,MAAM,EAC7B,cAAc,EAAE,MAAM,GACrB,mBAAmB,CAgBrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CAoBnE"}
@@ -0,0 +1,129 @@
1
+ // Policy pack versioning — semver parsing, range checking, and compatibility validation.
2
+ // Zero external dependencies. Supports the subset of semver needed for policy packs.
3
+ const SEMVER_REGEX = /^(\d+)\.(\d+)\.(\d+)$/;
4
+ /**
5
+ * Parse a semver string into its components.
6
+ * Returns null if the string is not a valid semver.
7
+ */
8
+ export function parseSemver(version) {
9
+ const match = version.trim().match(SEMVER_REGEX);
10
+ if (!match)
11
+ return null;
12
+ return {
13
+ major: parseInt(match[1], 10),
14
+ minor: parseInt(match[2], 10),
15
+ patch: parseInt(match[3], 10),
16
+ };
17
+ }
18
+ /**
19
+ * Compare two semver versions.
20
+ * Returns -1 if a < b, 0 if a === b, 1 if a > b.
21
+ */
22
+ export function compareSemver(a, b) {
23
+ if (a.major !== b.major)
24
+ return a.major < b.major ? -1 : 1;
25
+ if (a.minor !== b.minor)
26
+ return a.minor < b.minor ? -1 : 1;
27
+ if (a.patch !== b.patch)
28
+ return a.patch < b.patch ? -1 : 1;
29
+ return 0;
30
+ }
31
+ /**
32
+ * Check if a version satisfies a version range.
33
+ *
34
+ * Supported range formats:
35
+ * - Exact: `"1.2.3"` — must match exactly
36
+ * - Greater-or-equal: `">=1.2.3"` — version must be >= range
37
+ * - Caret: `"^1.2.3"` — compatible with (same major, >= minor.patch)
38
+ * - Tilde: `"~1.2.3"` — reasonably close (same major.minor, >= patch)
39
+ */
40
+ export function satisfiesRange(version, range) {
41
+ const trimmed = range.trim();
42
+ if (trimmed.startsWith('>=')) {
43
+ const rangeVer = parseSemver(trimmed.slice(2));
44
+ const ver = parseSemver(version);
45
+ if (!rangeVer || !ver)
46
+ return false;
47
+ return compareSemver(ver, rangeVer) >= 0;
48
+ }
49
+ if (trimmed.startsWith('^')) {
50
+ const rangeVer = parseSemver(trimmed.slice(1));
51
+ const ver = parseSemver(version);
52
+ if (!rangeVer || !ver)
53
+ return false;
54
+ // Same major, >= minor.patch
55
+ if (ver.major !== rangeVer.major)
56
+ return false;
57
+ if (ver.minor > rangeVer.minor)
58
+ return true;
59
+ if (ver.minor === rangeVer.minor)
60
+ return ver.patch >= rangeVer.patch;
61
+ return false;
62
+ }
63
+ if (trimmed.startsWith('~')) {
64
+ const rangeVer = parseSemver(trimmed.slice(1));
65
+ const ver = parseSemver(version);
66
+ if (!rangeVer || !ver)
67
+ return false;
68
+ // Same major.minor, >= patch
69
+ if (ver.major !== rangeVer.major)
70
+ return false;
71
+ if (ver.minor !== rangeVer.minor)
72
+ return false;
73
+ return ver.patch >= rangeVer.patch;
74
+ }
75
+ // Exact match
76
+ const rangeVer = parseSemver(trimmed);
77
+ const ver = parseSemver(version);
78
+ if (!rangeVer || !ver)
79
+ return false;
80
+ return compareSemver(ver, rangeVer) === 0;
81
+ }
82
+ /**
83
+ * Check if a policy pack is compatible with the current AgentGuard version.
84
+ *
85
+ * @param packAgentguardVersion — the `agentguardVersion` range from the pack (e.g., ">=2.0.0")
86
+ * @param currentVersion — the running AgentGuard version (e.g., "2.2.0")
87
+ */
88
+ export function checkCompatibility(packAgentguardVersion, currentVersion) {
89
+ const current = parseSemver(currentVersion);
90
+ if (!current) {
91
+ return { compatible: true, reason: `Cannot parse current version "${currentVersion}"` };
92
+ }
93
+ if (!satisfiesRange(currentVersion, packAgentguardVersion)) {
94
+ return {
95
+ compatible: false,
96
+ reason: `Pack requires AgentGuard ${packAgentguardVersion} ` +
97
+ `but current version is ${currentVersion}`,
98
+ };
99
+ }
100
+ return { compatible: true };
101
+ }
102
+ /**
103
+ * Parse a pack reference that may include a version constraint.
104
+ *
105
+ * Supports `"pack-name@^1.2.0"` syntax where the `@version` suffix
106
+ * specifies a version pin for the pack's own version.
107
+ *
108
+ * Scoped npm packages (e.g., `@agentguard/security-pack@^1.0.0`) are
109
+ * handled by splitting on the last `@`.
110
+ */
111
+ export function parsePackReference(ref) {
112
+ // Find the last '@' that is not at position 0 (scoped packages start with @)
113
+ const lastAt = ref.lastIndexOf('@');
114
+ if (lastAt <= 0) {
115
+ // No version constraint, or the only @ is the scope prefix
116
+ return { ref };
117
+ }
118
+ const possibleVersion = ref.slice(lastAt + 1);
119
+ // Check if what follows the @ looks like a version constraint
120
+ if (/^[~^>=]*\d/.test(possibleVersion)) {
121
+ return {
122
+ ref: ref.slice(0, lastAt),
123
+ versionConstraint: possibleVersion,
124
+ };
125
+ }
126
+ // Not a version constraint (e.g., just part of a package name)
127
+ return { ref };
128
+ }
129
+ //# sourceMappingURL=pack-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack-version.js","sourceRoot":"","sources":["../src/pack-version.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export type RiskLevel = 'danger' | 'warning' | 'info';
2
+ export interface RiskFlag {
3
+ level: RiskLevel;
4
+ message: string;
5
+ pattern: string;
6
+ }
7
+ export type TrustClass = 'implicitly_trusted' | 'trust_gated';
8
+ export interface PolicyTrustResult {
9
+ trustClass: TrustClass;
10
+ status: 'trusted' | 'untrusted' | 'content_changed';
11
+ riskFlags: RiskFlag[];
12
+ }
13
+ /**
14
+ * Pure function. Regex-based pattern matching on policy YAML content to detect
15
+ * risky configurations. Returns an array of risk flags (empty for safe policies).
16
+ */
17
+ export declare function analyzePolicyRisk(content: string): RiskFlag[];
18
+ /**
19
+ * Pure function. Determines trust classification based on path location.
20
+ * - Home dir paths → implicitly_trusted
21
+ * - Explicit CLI flag (--policy) → implicitly_trusted
22
+ * - Project-local files → trust_gated
23
+ */
24
+ export declare function classifyPolicyLocation(policyPath: string, options?: {
25
+ isExplicitCliFlag?: boolean;
26
+ }): TrustClass;
27
+ /**
28
+ * Non-interactive trust gate. Reads trust store + file hash.
29
+ * No stdin/stdout prompts — interactive prompting lives in the CLI trust command.
30
+ *
31
+ * 1. Classify location → if implicitly_trusted, return early with status: 'trusted'
32
+ * 2. If trust_gated, check trust store via verifyTrust() from @red-codes/core
33
+ * 3. CI override: if isCiTrustOverride() returns true, treat as 'trusted'
34
+ */
35
+ export declare function verifyPolicyTrust(policyPath: string, options?: {
36
+ isExplicitCliFlag?: boolean;
37
+ }): Promise<PolicyTrustResult>;
38
+ //# sourceMappingURL=policy-trust.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-trust.d.ts","sourceRoot":"","sources":["../src/policy-trust.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,GAAG,oBAAoB,GAAG,aAAa,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,iBAAiB,CAAC;IACpD,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AA+DD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAW7D;AAMD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GACxC,UAAU,CAUZ;AAMD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GACxC,OAAO,CAAC,iBAAiB,CAAC,CAyB5B"}
@@ -0,0 +1,119 @@
1
+ // Policy trust verification with risk analysis.
2
+ // Non-interactive — no stdin/stdout prompts.
3
+ // Interactive prompting lives in the CLI trust command.
4
+ import { readFileSync } from 'node:fs';
5
+ import { homedir } from 'node:os';
6
+ import { verifyTrust, isCiTrustOverride } from '@red-codes/core';
7
+ const RISK_PATTERNS = [
8
+ {
9
+ level: 'danger',
10
+ regex: /allow\s*:\s*["']?\*["']?/,
11
+ message: 'Wildcard allow detected — all actions will be permitted',
12
+ patternStr: 'allow: "*"',
13
+ },
14
+ {
15
+ level: 'danger',
16
+ regex: /(?:secret_exposure|protected_branches|blast_radius|test_before_push|no_force_push)\s*:\s*false/,
17
+ message: 'Disabled security invariant detected',
18
+ patternStr: '<invariant>: false',
19
+ },
20
+ {
21
+ level: 'danger',
22
+ regex: /enabled\s*:\s*false/,
23
+ message: 'Invariant explicitly disabled via enabled: false',
24
+ patternStr: 'enabled: false',
25
+ },
26
+ {
27
+ level: 'warning',
28
+ regex: /scope\s*:\s*["']?\*\*["']?/,
29
+ message: 'Broad scope pattern "**" matches all paths',
30
+ patternStr: 'scope: "**"',
31
+ },
32
+ {
33
+ level: 'warning',
34
+ regex: /files\s*:\s*\[["']?\*\*["']?\]/,
35
+ message: 'Broad files pattern ["**"] matches all files',
36
+ patternStr: 'files: ["**"]',
37
+ },
38
+ {
39
+ level: 'warning',
40
+ regex: /lockdownThreshold\s*:\s*(\d+)/,
41
+ message: 'High lockdown threshold — escalation to LOCKDOWN will be delayed',
42
+ patternStr: 'lockdownThreshold: >20',
43
+ customCheck: (content) => {
44
+ const match = /lockdownThreshold\s*:\s*(\d+)/.exec(content);
45
+ if (!match)
46
+ return false;
47
+ return parseInt(match[1], 10) > 20;
48
+ },
49
+ },
50
+ ];
51
+ // ---------------------------------------------------------------------------
52
+ // analyzePolicyRisk
53
+ // ---------------------------------------------------------------------------
54
+ /**
55
+ * Pure function. Regex-based pattern matching on policy YAML content to detect
56
+ * risky configurations. Returns an array of risk flags (empty for safe policies).
57
+ */
58
+ export function analyzePolicyRisk(content) {
59
+ const flags = [];
60
+ for (const rp of RISK_PATTERNS) {
61
+ const matched = rp.customCheck ? rp.customCheck(content) : rp.regex.test(content);
62
+ if (matched) {
63
+ flags.push({ level: rp.level, message: rp.message, pattern: rp.patternStr });
64
+ }
65
+ }
66
+ return flags;
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // classifyPolicyLocation
70
+ // ---------------------------------------------------------------------------
71
+ /**
72
+ * Pure function. Determines trust classification based on path location.
73
+ * - Home dir paths → implicitly_trusted
74
+ * - Explicit CLI flag (--policy) → implicitly_trusted
75
+ * - Project-local files → trust_gated
76
+ */
77
+ export function classifyPolicyLocation(policyPath, options) {
78
+ if (options?.isExplicitCliFlag)
79
+ return 'implicitly_trusted';
80
+ const home = homedir();
81
+ if (policyPath.startsWith('~') || policyPath.startsWith('$HOME') || policyPath.startsWith(home)) {
82
+ return 'implicitly_trusted';
83
+ }
84
+ return 'trust_gated';
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // verifyPolicyTrust
88
+ // ---------------------------------------------------------------------------
89
+ /**
90
+ * Non-interactive trust gate. Reads trust store + file hash.
91
+ * No stdin/stdout prompts — interactive prompting lives in the CLI trust command.
92
+ *
93
+ * 1. Classify location → if implicitly_trusted, return early with status: 'trusted'
94
+ * 2. If trust_gated, check trust store via verifyTrust() from @red-codes/core
95
+ * 3. CI override: if isCiTrustOverride() returns true, treat as 'trusted'
96
+ */
97
+ export async function verifyPolicyTrust(policyPath, options) {
98
+ const trustClass = classifyPolicyLocation(policyPath, options);
99
+ // Read file content for risk analysis
100
+ let content = '';
101
+ try {
102
+ content = readFileSync(policyPath, 'utf8');
103
+ }
104
+ catch {
105
+ // If file can't be read, proceed without risk analysis
106
+ }
107
+ const riskFlags = analyzePolicyRisk(content);
108
+ if (trustClass === 'implicitly_trusted') {
109
+ return { trustClass, status: 'trusted', riskFlags };
110
+ }
111
+ // CI override: treat project-local policy as trusted in CI environments
112
+ if (isCiTrustOverride()) {
113
+ return { trustClass, status: 'trusted', riskFlags };
114
+ }
115
+ // Delegate to trust store for trust-gated locations
116
+ const storeStatus = await verifyTrust(policyPath);
117
+ return { trustClass, status: storeStatus, riskFlags };
118
+ }
119
+ //# sourceMappingURL=policy-trust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-trust.js","sourceRoot":"","sources":["../src/policy-trust.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { LoadedPolicy, PersonaCondition, ForecastCondition } from './evaluator.js';
2
+ import type { AgentPersona } from '@red-codes/core';
3
+ export interface YamlPersonaDef {
4
+ model?: string;
5
+ provider?: string;
6
+ runtime?: string;
7
+ version?: string;
8
+ trustTier?: string;
9
+ autonomy?: string;
10
+ riskTolerance?: string;
11
+ role?: string;
12
+ tags?: string[];
13
+ }
14
+ export interface YamlPolicyDef {
15
+ id?: string;
16
+ name?: string;
17
+ description?: string;
18
+ severity?: number;
19
+ version?: string;
20
+ agentguardVersion?: string;
21
+ extends?: string[];
22
+ persona?: YamlPersonaDef;
23
+ rules?: YamlRule[];
24
+ /** Kernel invariant IDs to disable (human-operator override) */
25
+ disabledInvariants?: string[];
26
+ /** Top-level enforcement mode: 'monitor' (warn) or 'enforce' (block) */
27
+ mode?: 'monitor' | 'enforce';
28
+ /** Named policy pack to apply (e.g., 'essentials', 'strict') */
29
+ pack?: string;
30
+ /** Per-invariant mode overrides: invariant ID → 'monitor' | 'enforce' */
31
+ invariantModes?: Record<string, 'monitor' | 'enforce'>;
32
+ }
33
+ interface YamlRule {
34
+ action?: string | string[];
35
+ effect?: string;
36
+ target?: string;
37
+ branches?: string[];
38
+ reason?: string;
39
+ limit?: number;
40
+ requireTests?: boolean;
41
+ requireFormat?: boolean;
42
+ requireWorktree?: boolean;
43
+ persona?: PersonaCondition;
44
+ intervention?: string;
45
+ forecast?: ForecastCondition;
46
+ }
47
+ export declare function parseYamlPolicy(yaml: string): YamlPolicyDef;
48
+ /** Convert a YamlPersonaDef to an AgentPersona (for policy defaults). */
49
+ export declare function yamlPersonaToAgentPersona(def: YamlPersonaDef): AgentPersona;
50
+ export declare function loadYamlPolicy(yaml: string, defaultId?: string): LoadedPolicy;
51
+ export declare function loadYamlPolicies(yaml: string): LoadedPolicy[];
52
+ export {};
53
+ //# sourceMappingURL=yaml-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-loader.d.ts","sourceRoot":"","sources":["../src/yaml-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACpG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,wEAAwE;IACxE,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;CACxD;AAED,UAAU,QAAQ;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAiJD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA6Q3D;AAgHD,yEAAyE;AACzE,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,cAAc,GAAG,YAAY,CAiB3E;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CA0C7E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAE7D"}