praxis-sec 1.2.2 → 1.2.4
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/README.md +84 -115
- package/ai-defense/cost-protection.md +6 -0
- package/ai-defense/llm-security-checklist.md +6 -0
- package/ai-defense/system-prompt-armor.md +7 -1
- package/checklists/launch-day.md +6 -7
- package/cli/agents/agent-telemetry-agent.js +2 -0
- package/cli/agents/api-fuzzer.js +2 -2
- package/cli/agents/git-history-scanner.js +14 -15
- package/cli/agents/html-reporter.js +2 -1
- package/cli/agents/memory-poisoning-agent.js +1 -5
- package/cli/commands/agent-fix.js +3 -1
- package/cli/commands/audit.js +1271 -1231
- package/cli/commands/autofix.js +32 -13
- package/cli/commands/baseline.js +2 -1
- package/cli/commands/benchmark.js +2 -1
- package/cli/commands/ci.js +7 -4
- package/cli/commands/env-audit.js +4 -2
- package/cli/commands/fix.js +2 -1
- package/cli/commands/mcp.js +52 -50
- package/cli/commands/remediate.js +2 -1
- package/cli/commands/rotate.js +2 -1
- package/cli/commands/scan-mcp.js +20 -9
- package/cli/commands/scan.js +15 -7
- package/cli/commands/score.js +2 -1
- package/cli/commands/vibe-check.js +2 -1
- package/cli/commands/watch.js +2 -1
- package/cli/core/glob.js +7 -5
- package/cli/core/paths.js +4 -4
- package/cli/core/web/jobs.js +2 -0
- package/cli/data/documented-secret-examples.json +14 -0
- package/cli/utils/entropy.js +19 -0
- package/cli/utils/hermes-tool-registry.js +11 -9
- package/configs/firebase/security-checklist.md +3 -3
- package/configs/supabase/security-checklist.md +19 -21
- package/docs/RELEASE-1.2.4.md +85 -0
- package/docs/RELEASING.md +51 -0
- package/docs/THIRD_PARTY_NOTICES.md +8 -0
- package/docs/THREAT_INTEL.md +4 -2
- package/docs/USAGE.md +97 -76
- package/package.json +82 -81
- package/snippets/README.md +6 -0
- package/snippets/auth/jwt-checklist.md +14 -13
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
MAX_FILE_SIZE,
|
|
31
31
|
loadGitignorePatterns
|
|
32
32
|
} from '../utils/patterns.js';
|
|
33
|
-
import { isHighEntropyMatch, getConfidence } from '../utils/entropy.js';
|
|
33
|
+
import { isHighEntropyMatch, getConfidence, isDocumentedSecretExample } from '../utils/entropy.js';
|
|
34
34
|
import fg from '../core/glob.js';
|
|
35
35
|
|
|
36
36
|
// =============================================================================
|
|
@@ -135,6 +135,7 @@ export async function vibeCheckCommand(targetPath = '.', options = {}) {
|
|
|
135
135
|
pattern.pattern.lastIndex = 0;
|
|
136
136
|
let match;
|
|
137
137
|
while ((match = pattern.pattern.exec(line)) !== null) {
|
|
138
|
+
if (isDocumentedSecretExample(pattern.name, match[0])) continue;
|
|
138
139
|
if (pattern.requiresEntropyCheck && !isHighEntropyMatch(match[0])) continue;
|
|
139
140
|
secretFindings.push({
|
|
140
141
|
file, line: lineNum + 1, column: match.index + 1,
|
package/cli/commands/watch.js
CHANGED
|
@@ -16,7 +16,7 @@ import chalk from 'chalk';
|
|
|
16
16
|
import { displayPath } from '../core/paths.js';
|
|
17
17
|
import { execFileSync } from 'child_process';
|
|
18
18
|
import { SKIP_DIRS, SKIP_EXTENSIONS, SKIP_FILENAMES, SECRET_PATTERNS, SECURITY_PATTERNS } from '../utils/patterns.js';
|
|
19
|
-
import { isHighEntropyMatch, getConfidence } from '../utils/entropy.js';
|
|
19
|
+
import { isHighEntropyMatch, getConfidence, isDocumentedSecretExample } from '../utils/entropy.js';
|
|
20
20
|
import * as output from '../utils/output.js';
|
|
21
21
|
import { ScoringEngine } from '../agents/scoring-engine.js';
|
|
22
22
|
|
|
@@ -175,6 +175,7 @@ function scanFile(filePath, patterns) {
|
|
|
175
175
|
pattern.pattern.lastIndex = 0;
|
|
176
176
|
let match;
|
|
177
177
|
while ((match = pattern.pattern.exec(line)) !== null) {
|
|
178
|
+
if (isDocumentedSecretExample(pattern.name, match[0])) continue;
|
|
178
179
|
if (pattern.requiresEntropyCheck && !isHighEntropyMatch(match[0])) continue;
|
|
179
180
|
findings.push({
|
|
180
181
|
line: i + 1,
|
package/cli/core/glob.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scanner file discovery boundary. Target-controlled patterns are bounded before
|
|
3
|
-
*
|
|
3
|
+
* the glob parser sees them, including pathological ignore patterns.
|
|
4
4
|
* Directory symlinks must not turn a project scan into a scan of the host.
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
6
|
+
import { glob as discover, globSync } from 'tinyglobby';
|
|
7
|
+
import { validateDir } from './fs.js';
|
|
7
8
|
|
|
8
9
|
const MAX_PATTERNS = 4096;
|
|
9
10
|
const MAX_LENGTH = 8192;
|
|
@@ -42,15 +43,16 @@ export function validateGlobPatterns(patterns) {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function safeOptions(patterns, options) {
|
|
46
|
+
if (options.cwd && !validateDir(options.cwd, { exitOnMissing: false })) throw new Error('Scan root must be an existing directory');
|
|
45
47
|
validateGlobPatterns(patterns);
|
|
46
48
|
if (options.ignore) validateGlobPatterns(options.ignore);
|
|
47
|
-
return { ...options, followSymbolicLinks: false };
|
|
49
|
+
return { ...options, expandDirectories: false, followSymbolicLinks: false };
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
function glob(patterns, options = {}) {
|
|
51
|
-
return
|
|
53
|
+
return discover(patterns, safeOptions(patterns, options));
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
glob.sync = (patterns, options = {}) =>
|
|
56
|
+
glob.sync = (patterns, options = {}) => globSync(patterns, safeOptions(patterns, options));
|
|
55
57
|
|
|
56
58
|
export default glob;
|
package/cli/core/paths.js
CHANGED
|
@@ -35,7 +35,7 @@ const toSlash = (p) => String(p).split(path.sep).join('/').replace(/\\/g, '/');
|
|
|
35
35
|
// normally come from the host's own glob, but a path read back from a report or
|
|
36
36
|
// a cache can carry the other platform's shape, and treating it as relative would
|
|
37
37
|
// print a drive letter straight into the output. Same guard sarif.js uses.
|
|
38
|
-
const isAbsoluteLike = (s) => path.isAbsolute(s) || /^[a-zA-Z]:[\\/]/.test(s);
|
|
38
|
+
const isAbsoluteLike = (s) => path.isAbsolute(s) || /^[a-zA-Z]:[\\/]/.test(s) || /^\\\\/.test(s);
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Render a finding's file for display.
|
|
@@ -58,7 +58,7 @@ export function displayPath(file, root) {
|
|
|
58
58
|
if (root) {
|
|
59
59
|
const rel = path.relative(root, s);
|
|
60
60
|
// `rel` starting with '..' means the file is outside the scan root.
|
|
61
|
-
if (rel && !rel.startsWith(
|
|
61
|
+
if (rel && rel !== '..' && !rel.startsWith(`..${path.sep}`) && !path.isAbsolute(rel)) return toSlash(rel);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
const home = os.homedir();
|
|
@@ -68,7 +68,7 @@ export function displayPath(file, root) {
|
|
|
68
68
|
|
|
69
69
|
// Outside the root and outside home: identify the file without publishing the
|
|
70
70
|
// local directory layout.
|
|
71
|
-
return path.basename(s);
|
|
71
|
+
return path.posix.basename(toSlash(s));
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/**
|
|
@@ -88,4 +88,4 @@ export function normalizeFindingPaths(findings, root) {
|
|
|
88
88
|
return findings;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
export default displayPath;
|
|
91
|
+
export default displayPath;
|
package/cli/core/web/jobs.js
CHANGED
|
@@ -172,6 +172,8 @@ export async function runScanWithOrchestrator(rootPath, onProgress) {
|
|
|
172
172
|
},
|
|
173
173
|
});
|
|
174
174
|
|
|
175
|
+
if (agentResults.some(agent => !agent.success)) throw new Error('Scan incomplete: one or more agents failed');
|
|
176
|
+
|
|
175
177
|
let score = 100;
|
|
176
178
|
let grade = 'A';
|
|
177
179
|
let categories = {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"lastReviewed": "2026-10-07",
|
|
4
|
+
"description": "Exact provider-documented non-working credential identifiers. No substring, test-directory, or history-wide exemptions.",
|
|
5
|
+
"examples": [
|
|
6
|
+
{
|
|
7
|
+
"pattern": "AWS Access Key ID",
|
|
8
|
+
"aliases": ["AGENT_LOG_EXPOSED_AWS_KEY"],
|
|
9
|
+
"value": "AKIAIOSFODNN7EXAMPLE",
|
|
10
|
+
"source": "https://docs.aws.amazon.com/AmazonS3/latest/developerguide/RESTAuthentication.html",
|
|
11
|
+
"reason": "AWS explicitly labels this identifier a non-working example credential."
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
package/cli/utils/entropy.js
CHANGED
|
@@ -19,6 +19,25 @@
|
|
|
19
19
|
* Patterns with known prefixes (sk-ant-, ghp_, AKIA...) are already precise enough.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
|
|
24
|
+
const documentedExamples = new Map();
|
|
25
|
+
try {
|
|
26
|
+
const catalog = JSON.parse(fs.readFileSync(new URL('../data/documented-secret-examples.json', import.meta.url), 'utf8'));
|
|
27
|
+
for (const entry of catalog.examples || []) {
|
|
28
|
+
if (typeof entry.pattern !== 'string' || typeof entry.value !== 'string') continue;
|
|
29
|
+
for (const name of [entry.pattern, ...(Array.isArray(entry.aliases) ? entry.aliases : [])]) {
|
|
30
|
+
if (typeof name !== 'string') continue;
|
|
31
|
+
if (!documentedExamples.has(name)) documentedExamples.set(name, new Set());
|
|
32
|
+
documentedExamples.get(name).add(entry.value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} catch { /* Missing example data must never suppress unknown credentials. */ }
|
|
36
|
+
|
|
37
|
+
export function isDocumentedSecretExample(patternName, matched) {
|
|
38
|
+
return documentedExamples.get(patternName)?.has(extractSecretValue(matched)) === true;
|
|
39
|
+
}
|
|
40
|
+
|
|
22
41
|
// =============================================================================
|
|
23
42
|
// ENTROPY CALCULATION
|
|
24
43
|
// =============================================================================
|
|
@@ -62,7 +62,9 @@ export const HERMES_TOOLS = [
|
|
|
62
62
|
},
|
|
63
63
|
handler: async ({ path: scanPath, severity = 'medium', deep = false }) => {
|
|
64
64
|
const { auditCommand } = await import('../commands/audit.js');
|
|
65
|
-
|
|
65
|
+
const report = await auditCommand(scanPath, { deep, _agenticInner: true, deps: false, noAi: true });
|
|
66
|
+
const ranks = { critical: 4, high: 3, medium: 2, low: 1 };
|
|
67
|
+
return { ...report, findings: report.findings.filter(f => (ranks[f.severity] ?? 0) >= (ranks[severity] ?? 0)) };
|
|
66
68
|
},
|
|
67
69
|
},
|
|
68
70
|
|
|
@@ -86,7 +88,7 @@ export const HERMES_TOOLS = [
|
|
|
86
88
|
},
|
|
87
89
|
handler: async ({ target }) => {
|
|
88
90
|
const { scanMcpCommand } = await import('../commands/scan-mcp.js');
|
|
89
|
-
return scanMcpCommand(target, { json: true });
|
|
91
|
+
return scanMcpCommand(target, { json: true, quiet: true });
|
|
90
92
|
},
|
|
91
93
|
},
|
|
92
94
|
|
|
@@ -115,7 +117,7 @@ export const HERMES_TOOLS = [
|
|
|
115
117
|
},
|
|
116
118
|
handler: async ({ path: projectPath, severity = 'medium' }) => {
|
|
117
119
|
const { mcpGetFindings } = await import('../commands/mcp.js');
|
|
118
|
-
return mcpGetFindings({ projectPath, severity });
|
|
120
|
+
return mcpGetFindings({ reportPath: path.join(projectPath, '.praxis', 'last-report.json'), severity });
|
|
119
121
|
},
|
|
120
122
|
},
|
|
121
123
|
|
|
@@ -123,7 +125,7 @@ export const HERMES_TOOLS = [
|
|
|
123
125
|
name: 'praxis_suppress_finding',
|
|
124
126
|
description:
|
|
125
127
|
'Suppress a known-safe finding by inserting an inline praxis-ignore comment ' +
|
|
126
|
-
'
|
|
128
|
+
'on the flagged source line. Use only when the finding is a ' +
|
|
127
129
|
'confirmed false positive and you can document why it is safe.',
|
|
128
130
|
parameters: {
|
|
129
131
|
type: 'object',
|
|
@@ -184,11 +186,11 @@ export const HERMES_TOOLS = [
|
|
|
184
186
|
// =============================================================================
|
|
185
187
|
|
|
186
188
|
const KNOWN_HASHES = {
|
|
187
|
-
praxis_audit: '
|
|
188
|
-
praxis_scan_mcp: '
|
|
189
|
-
praxis_get_findings: '
|
|
190
|
-
praxis_suppress_finding: '
|
|
191
|
-
praxis_memory_list: '
|
|
189
|
+
praxis_audit: '4bdb0dafe1efea27',
|
|
190
|
+
praxis_scan_mcp: '99c278579ccc7e38',
|
|
191
|
+
praxis_get_findings: '8c3b10c970f047ab',
|
|
192
|
+
praxis_suppress_finding: '3cedaa6e7ae974ae',
|
|
193
|
+
praxis_memory_list: '9d405b87e81c7263',
|
|
192
194
|
};
|
|
193
195
|
|
|
194
196
|
function toolHash(tool) {
|
|
@@ -24,11 +24,11 @@ allow read, write: if request.time < timestamp.date(2024, 12, 31);
|
|
|
24
24
|
### 2. [ ] Firestore rules require authentication
|
|
25
25
|
|
|
26
26
|
```javascript
|
|
27
|
-
//
|
|
27
|
+
// Authentication check alone: insufficient for private per-user data
|
|
28
28
|
allow read, write: if request.auth != null;
|
|
29
29
|
|
|
30
30
|
// BETTER: Requires authentication AND ownership
|
|
31
|
-
allow read, write: if request.auth.uid == userId;
|
|
31
|
+
allow read, write: if request.auth != null && request.auth.uid == userId;
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
### 3. [ ] Storage rules have file type validation
|
|
@@ -49,7 +49,7 @@ allow write: if request.resource.size < 5 * 1024 * 1024;
|
|
|
49
49
|
### 5. [ ] Default deny rule at the end
|
|
50
50
|
|
|
51
51
|
```javascript
|
|
52
|
-
//
|
|
52
|
+
// Explicit default deny. Matching allow rules are additive; this does not override another allow.
|
|
53
53
|
match /{document=**} {
|
|
54
54
|
allow read, write: if false;
|
|
55
55
|
}
|
|
@@ -2,42 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
**Complete this checklist before launching your Supabase-powered app.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Follow [Supabase RLS guidance](https://supabase.com/docs/guides/database/postgres/row-level-security). Test allow and deny behavior for each operation and role; these examples are not proof of access isolation.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Critical: Row Level Security (RLS)
|
|
10
10
|
|
|
11
|
-
### 1. [ ] RLS is
|
|
11
|
+
### 1. [ ] RLS is enabled on tables exposed to application users
|
|
12
12
|
|
|
13
13
|
```sql
|
|
14
14
|
-- Check which tables DON'T have RLS
|
|
15
|
-
SELECT schemaname, tablename
|
|
16
|
-
FROM
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
);
|
|
15
|
+
SELECT n.nspname AS schemaname, c.relname AS tablename
|
|
16
|
+
FROM pg_class AS c
|
|
17
|
+
JOIN pg_namespace AS n ON n.oid = c.relnamespace
|
|
18
|
+
WHERE n.nspname = 'public'
|
|
19
|
+
AND c.relkind IN ('r', 'p')
|
|
20
|
+
AND NOT c.relrowsecurity;
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
**
|
|
23
|
+
**Review exposed tables and enable RLS with tested policies and grants:**
|
|
25
24
|
```sql
|
|
26
25
|
ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
### 2. [ ]
|
|
28
|
+
### 2. [ ] Exposed tables have the policies needed for intended operations
|
|
30
29
|
|
|
31
30
|
```sql
|
|
32
|
-
--
|
|
33
|
-
SELECT
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
38
|
-
AND
|
|
39
|
-
SELECT
|
|
40
|
-
);
|
|
31
|
+
-- RLS tables with no policies: ordinary roles are denied, but bypass roles differ.
|
|
32
|
+
SELECT n.nspname AS schemaname, c.relname AS tablename
|
|
33
|
+
FROM pg_class AS c
|
|
34
|
+
JOIN pg_namespace AS n ON n.oid = c.relnamespace
|
|
35
|
+
WHERE n.nspname = 'public'
|
|
36
|
+
AND c.relkind IN ('r', 'p')
|
|
37
|
+
AND c.relrowsecurity
|
|
38
|
+
AND NOT EXISTS (SELECT 1 FROM pg_policy AS p WHERE p.polrelid = c.oid);
|
|
41
39
|
```
|
|
42
40
|
|
|
43
41
|
### 3. [ ] Policies use `auth.uid()` not hardcoded values
|
|
@@ -97,7 +95,7 @@ grep -r "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ./src
|
|
|
97
95
|
The `anon` key is designed to be public, but only if RLS is properly configured.
|
|
98
96
|
|
|
99
97
|
```typescript
|
|
100
|
-
// Frontend:
|
|
98
|
+
// Frontend: use the appropriate public key with tested RLS policies and grants
|
|
101
99
|
const supabase = createClient(url, anonKey);
|
|
102
100
|
|
|
103
101
|
// Server: Use service_role key (for admin operations)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Praxis 1.2.4
|
|
2
|
+
|
|
3
|
+
This patch corrects cases where a scan could report success without examining the
|
|
4
|
+
requested target, and fixes project targeting in the older annotation loop.
|
|
5
|
+
|
|
6
|
+
- Full, secret, and CI scans require a directory. A file supplied as a scan root
|
|
7
|
+
now produces an error instead of a false empty result. The VS Code current-file
|
|
8
|
+
action scans its workspace and selects diagnostics for the requested file.
|
|
9
|
+
- Full-scan JSON includes `scanComplete`, `scanErrors`, and `dependencyAudit`.
|
|
10
|
+
Failed discovery, failed agents, unavailable dependency audits, or failed
|
|
11
|
+
requested legal scans mark the result incomplete and exit unsuccessfully.
|
|
12
|
+
Findings alone still do not fail a normal scan; use `scan ci` for severity gates.
|
|
13
|
+
- Incomplete scans do not update scan cache, score history, or the playbook, and
|
|
14
|
+
cannot start the annotation loop or satisfy fix verification. HTML reports show
|
|
15
|
+
an incomplete warning; the web runner refuses failed-agent results.
|
|
16
|
+
A failed annotation-loop verification also overrides `--fail-below`; JSON
|
|
17
|
+
reports the failure once without inner-scan progress text. Reports are generated
|
|
18
|
+
after verification so HTML and machine-readable status agree.
|
|
19
|
+
- `scan full --timeout` now reaches the orchestrator.
|
|
20
|
+
- Annotation targets resolve inside the requested project, including symlink
|
|
21
|
+
destinations. Protected scanner/Git paths and unsupported comment formats such
|
|
22
|
+
as JSON are rejected. Writes are atomic, and unchanged annotations are not
|
|
23
|
+
counted as applied. Multiple annotations in one file are inserted from the
|
|
24
|
+
bottom to preserve finding line numbers; replaying the same report is safe.
|
|
25
|
+
- In-root directories beginning with two dots retain their full relative path.
|
|
26
|
+
Foreign Windows backslash and UNC paths fall back to a safe basename.
|
|
27
|
+
- Memory-poisoning document discovery respects ignore rules and dependency
|
|
28
|
+
directories instead of reading ignored nested artifacts as project context.
|
|
29
|
+
- File discovery uses `tinyglobby` in place of the vulnerable
|
|
30
|
+
`fast-glob → micromatch → braces` chain. Directory expansion stays disabled,
|
|
31
|
+
brace limits and symlink boundaries remain enforced, and discovery has tests
|
|
32
|
+
for hidden files, exclusions, extglobs, literal directories, and async/sync parity.
|
|
33
|
+
- Exact provider-documented non-working credentials are recognized from an
|
|
34
|
+
attributed data catalog. Unknown credentials on the same line still produce
|
|
35
|
+
findings. History scans process all matches, distinguish credentials that share
|
|
36
|
+
the same masked display, and report operational failures as incomplete.
|
|
37
|
+
- Upload rules require request/upload filename evidence instead of treating
|
|
38
|
+
local package metadata or any variable named `filename` as a vulnerable upload.
|
|
39
|
+
- The independently versioned VS Code extension is prepared as 1.0.1. CLI calls
|
|
40
|
+
use executable/argument arrays instead of shell text, and default npx execution
|
|
41
|
+
forbids automatic package installation. Report fields are escaped, severity
|
|
42
|
+
classes are sanitized, and a Content-Security-Policy blocks remote content.
|
|
43
|
+
Windows npm launchers resolve to the CLI's JavaScript entry point, preserving
|
|
44
|
+
literal arguments without invoking a command shell.
|
|
45
|
+
|
|
46
|
+
- MCP suppression now writes on the matched line, preserves line endings, rejects
|
|
47
|
+
unsupported formats and non-integer lines, and writes atomically. MCP repository
|
|
48
|
+
scans use the current scoring API, expose agent failures as incomplete, and
|
|
49
|
+
reject file roots.
|
|
50
|
+
- Hermes handlers return structured audit/manifest results, read the explicit saved
|
|
51
|
+
report path, apply severity filtering, and register against corrected integrity
|
|
52
|
+
hashes. Default Hermes audits disclose skipped dependency checks.
|
|
53
|
+
- Documentation uses canonical commands, preserves errors, corrects CI examples,
|
|
54
|
+
describes data egress and score limitations, and provides a release procedure.
|
|
55
|
+
The Claude Code plugin instructions are independently versioned as 3.0.1.
|
|
56
|
+
|
|
57
|
+
## Validation and limitations
|
|
58
|
+
|
|
59
|
+
Release validation covers the CLI test suite on Node 18, 20, 22 and 24, lint,
|
|
60
|
+
extension compilation and runtime tests, scan determinism, a complete zero-critical
|
|
61
|
+
self-scan, local PR Action base/head comparison, and installed-package smoke tests.
|
|
62
|
+
The production dependency chain was removed rather than overridden; the reviewed
|
|
63
|
+
full dependency audit, including development dependencies, reports zero advisories.
|
|
64
|
+
Audit results reflect the advisory database at the time of verification.
|
|
65
|
+
|
|
66
|
+
AWS explicitly identifies the formerly reported fixture credential as
|
|
67
|
+
[non-working example data](https://docs.aws.amazon.com/AmazonS3/latest/developerguide/RESTAuthentication.html).
|
|
68
|
+
Only that exact identifier in AWS credential rules is exempted; tests retain
|
|
69
|
+
unknown credentials on the same line. History and test files are not excluded.
|
|
70
|
+
|
|
71
|
+
Noncritical heuristic findings and existing lint warnings remain. A self-scan
|
|
72
|
+
score is not a measurement of scanner accuracy. Live LLM provider behavior and
|
|
73
|
+
interactive VS Code UI behavior were not validated by these release checks.
|
|
74
|
+
|
|
75
|
+
## Distribution
|
|
76
|
+
|
|
77
|
+
The GitHub release, immutable `v1.2.4` tag, and floating Marketplace Action `v1`
|
|
78
|
+
are prepared from the same commit after its hosted CI succeeds. The release
|
|
79
|
+
includes the npm package tarball and a SHA-256 checksum. **npm publication is a
|
|
80
|
+
separate maintainer step**; a GitHub release does not change npm latest.
|
|
81
|
+
|
|
82
|
+
Use `Ganron007/Praxis@v1.2.4` to pin the Action. For CLI use before npm publication,
|
|
83
|
+
install the attached tarball or run from a checkout of this tag. After publication,
|
|
84
|
+
install `praxis-sec@1.2.4` from npm. See [the release procedure](RELEASING.md) for
|
|
85
|
+
the checks and publishing handoff.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Releasing Praxis
|
|
2
|
+
|
|
3
|
+
The CLI/npm package, GitHub Action, Claude Code plugin, and VS Code extension
|
|
4
|
+
have separate distribution surfaces. A GitHub release does not publish npm or
|
|
5
|
+
the VS Code extension.
|
|
6
|
+
|
|
7
|
+
## Prepare
|
|
8
|
+
|
|
9
|
+
1. Choose the CLI patch version and update `package.json`, both root lockfile
|
|
10
|
+
version fields, and `docs/RELEASE-<version>.md`.
|
|
11
|
+
2. Update public examples to the intended Action tag. Keep independently
|
|
12
|
+
versioned integrations consistent with their own manifests and lockfiles.
|
|
13
|
+
3. Run `npm ci` and `npm run release:check`. This checks CLI tests, lint,
|
|
14
|
+
production dependency advisories, scan determinism, a complete zero-critical
|
|
15
|
+
self-scan, editor compilation/runtime tests, package exclusions, and an
|
|
16
|
+
installed-package scan with redaction and cache parity.
|
|
17
|
+
4. Review `git diff --check` and the package contents. Keep `docs/internal/`,
|
|
18
|
+
runtime state, credentials, test fixtures, and local binaries out of Git and
|
|
19
|
+
the npm package.
|
|
20
|
+
|
|
21
|
+
## GitHub and Marketplace
|
|
22
|
+
|
|
23
|
+
1. Commit the complete release and push it. Wait for CI to pass on that exact
|
|
24
|
+
commit, including all four Node versions, determinism, package/editor checks,
|
|
25
|
+
and the local Action smoke test.
|
|
26
|
+
2. Create an annotated immutable version tag, such as `v1.2.4`, on that commit.
|
|
27
|
+
Never replace a previously published version tag with different source.
|
|
28
|
+
3. Pack the committed source with `npm pack`. Attach the tarball and its SHA-256
|
|
29
|
+
checksum to the GitHub release, using the reviewed release notes.
|
|
30
|
+
4. Advance the floating `v1` Action tag deliberately to the same commit. Check
|
|
31
|
+
the prior remote value first and protect the update against concurrent changes.
|
|
32
|
+
5. Verify the release, version tag, floating tag, assets, and successful CI all
|
|
33
|
+
refer to the reviewed source. Consumers can use the exact version tag or
|
|
34
|
+
commit instead of the floating tag.
|
|
35
|
+
|
|
36
|
+
## npm publication
|
|
37
|
+
|
|
38
|
+
The maintainer publishes npm separately from the same clean, committed checkout:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
git checkout v1.2.4
|
|
42
|
+
npm ci
|
|
43
|
+
npm publish
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`prepublishOnly` reruns the release gates and rejects an uncommitted working
|
|
47
|
+
tree or a version different from the committed package metadata. Authentication
|
|
48
|
+
and npm account requirements must be satisfied by the publishing maintainer.
|
|
49
|
+
After publication, confirm `npm view praxis-sec version dist-tags` and install
|
|
50
|
+
that exact registry version in a clean project. GitHub and npm may legitimately
|
|
51
|
+
show different versions until this step completes.
|
|
@@ -17,6 +17,14 @@ and attribution as required.
|
|
|
17
17
|
- **Source:** https://github.com/0x4D31/endpoint-ai-agent-abuse (v0.1.0)
|
|
18
18
|
- **License:** CC0-1.0 (public domain dedication) — https://creativecommons.org/publicdomain/zero/1.0/
|
|
19
19
|
|
|
20
|
+
## Documented non-working credential examples
|
|
21
|
+
|
|
22
|
+
- **File:** `cli/data/documented-secret-examples.json`
|
|
23
|
+
- **Source:** [AWS S3 authentication examples](https://docs.aws.amazon.com/AmazonS3/latest/developerguide/RESTAuthentication.html)
|
|
24
|
+
- Contains one exact identifier AWS labels non-working, with our own annotations.
|
|
25
|
+
No documentation prose is reproduced. This is factual example provenance, not
|
|
26
|
+
permission to suppress arbitrary credentials, test files, or repository history.
|
|
27
|
+
|
|
20
28
|
## Standards referenced (not vendored)
|
|
21
29
|
|
|
22
30
|
Findings are mapped to the following frameworks; their text is not reproduced:
|
package/docs/THREAT_INTEL.md
CHANGED
|
@@ -12,7 +12,9 @@ For everything else (general CLI usage, scanning, hooks, etc.), see the main
|
|
|
12
12
|
|
|
13
13
|
## 1. Commands
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Feed-update commands store caches under `~/.praxis/`. Scan commands also read
|
|
16
|
+
the selected project and can update its local Praxis state. Updates contact
|
|
17
|
+
configured remote sources; cached data is not a guarantee of current coverage.
|
|
16
18
|
|
|
17
19
|
| Command | What it does |
|
|
18
20
|
| --- | --- |
|
|
@@ -35,7 +37,7 @@ over no data.
|
|
|
35
37
|
praxis intel update
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Illustrative output (versions and counts depend on the fetched feeds):
|
|
39
41
|
|
|
40
42
|
```
|
|
41
43
|
Fetching sources...
|