Skip to content

Commit 8e8da1d

Browse files
committed
feat(T010): add AI usage inventory export
1 parent 659cfb6 commit 8e8da1d

20 files changed

Lines changed: 2692 additions & 421 deletions

docs/AI_USAGE_INVENTORY.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# AI Usage Inventory (AI-BOM)
2+
3+
The AI Usage Inventory provides a deterministic, structured, and backend-ready contract for inventorying AI assets within a repository.
4+
5+
## Purpose
6+
- Provide a standardized AI-BOM format.
7+
- Enable automated ingestion by Caesar Governance OS.
8+
- Support compliance and reporting without exposing sensitive data.
9+
- Maintain an offline/deterministic source of truth.
10+
11+
## Contract Structure
12+
The inventory follows the `schemas/ai-usage-inventory.schema.json` schema:
13+
14+
- **Metadata:** Schema version, tool version, and run timestamp.
15+
- **Components:** Grouped by detection category:
16+
- `provider_sdks`
17+
- `orchestration_frameworks`
18+
- `rag_vector_stack`
19+
- `model_artifacts`
20+
- `prompt_assets`
21+
- `config_signals`
22+
- **Governance:** Review requirements, export status, and safety flags.
23+
24+
## Integration
25+
The inventory is exported via the Caesar AI Scan CLI using:
26+
`--inventory-out <path>`
27+
`--inventory-report <path>` (optional markdown summary)

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "caesar-ai-scan",
3-
"version": "0.9.0",
3+
"version": "0.10.0",
44
"description": "Static-analysis CLI and CI/CD tool to inventory AI dependencies, framework usage, vector DBs, and credentials.",
55
"type": "module",
66
"main": "src/cli.mjs",
@@ -18,9 +18,11 @@
1818
"validate:site": "node scripts/validate-site.mjs",
1919
"history:sample": "node src/cli.mjs fixtures/sample-ai-project --format json --out tmp/sample-scan-result.json --export-evidence-candidates tmp/sample-evidence-candidates.json --review-out tmp/sample-review-workflow.json --export-pack tmp/sample-evidence-export-pack --history-dir tmp/sample-history --record-history --diff-previous --history-report tmp/sample-history/latest-diff.md",
2020
"validate:history": "node scripts/validate-scan-history.mjs",
21+
"inventory:sample": "node src/cli.mjs fixtures/sample-ai-frameworks-project --format json --out tmp/sample-scan-result.json --inventory-out tmp/sample-ai-usage-inventory.json --inventory-report tmp/sample-ai-usage-inventory.md",
22+
"validate:inventory": "node scripts/validate-ai-usage-inventory.mjs",
2123
"validate:rule-pack-v1": "node scripts/validate-rule-pack-v1.mjs",
2224
"reference:scan:setup": "node scripts/setup-ai-scan-reference-lab.mjs",
23-
"check:all-offline": "npm run check:syntax && npm run scan:sample && npm run validate:samples && npm run validate:rule-pack-v1 && npm run review:sample && npm run validate:review && npm run pack:sample && npm run validate:pack && npm run scope:sample && npm run validate:scope && npm run validate:history && npm run build:site && npm run validate:site"
25+
"check:all-offline": "npm run check:syntax && npm run scan:sample && npm run validate:samples && npm run validate:rule-pack-v1 && npm run review:sample && npm run validate:review && npm run pack:sample && npm run validate:pack && npm run scope:sample && npm run validate:scope && npm run validate:history && npm run inventory:sample && npm run validate:inventory && npm run build:site && npm run validate:site"
2426
},
2527
"keywords": [
2628
"ai",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { readFileSync, writeFileSync } from 'fs';
2+
import { resolve } from 'path';
3+
4+
const inventoryPath = resolve('tmp/sample-ai-usage-inventory.json');
5+
const inventory = JSON.parse(readFileSync(inventoryPath, 'utf8'));
6+
7+
console.log('🚀 Validating AI Usage Inventory...');
8+
9+
// 1. Validate Structure
10+
const requiredFields = ['schema_version', 'generated_at', 'tool_name', 'tool_version', 'inventory'];
11+
requiredFields.forEach(field => {
12+
if (!inventory[field]) throw new Error(`Missing required field: ${field}`);
13+
});
14+
15+
// 2. Validate Categories
16+
const categories = ['provider_sdks', 'orchestration_frameworks', 'rag_vector_stack', 'model_artifacts', 'prompt_assets', 'config_signals'];
17+
categories.forEach(cat => {
18+
if (!Array.isArray(inventory.inventory[cat])) throw new Error(`Category ${cat} is not an array`);
19+
});
20+
21+
// 3. Verify counts (minimum coverage)
22+
const minCoverage = {
23+
provider_sdks: 3,
24+
orchestration_frameworks: 4,
25+
rag_vector_stack: 5,
26+
prompt_assets: 2,
27+
model_artifacts: 3,
28+
config_signals: 4
29+
};
30+
31+
Object.entries(minCoverage).forEach(([cat, min]) => {
32+
const count = inventory.inventory[cat].length;
33+
if (count < min) throw new Error(`Insufficient findings for ${cat}: expected at least ${min}, found ${count}`);
34+
console.log(`✅ ${cat}: ${count} findings (>= ${min})`);
35+
});
36+
37+
// 4. Verify draft status
38+
if (inventory.export_status !== 'draft') throw new Error('Inventory must be in draft status');
39+
if (inventory.review_required !== true) throw new Error('Inventory must require review');
40+
41+
console.log('✅ All inventory validation assertions PASSED successfully.');

scripts/validate-samples.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function runValidation() {
2121
assert(result.schema_version === '0.5.0', 'Schema version should be 0.5.0');
2222
assert(result.scanner && result.scanner.name === 'caesar-ai-scan', 'Scanner name matches');
2323
// version is now 0.9.0
24-
assert(result.scanner.version === '0.9.0', `Scanner version should be 0.9.0, got ${result.scanner.version}`);
24+
assert(result.scanner.version === '0.10.0', `Scanner version should be 0.10.0, got ${result.scanner.version}`);
2525

2626
assert(result.scanned_at, 'scanned_at timestamp exists');
2727
assert(result.target === './fixtures/sample-ai-project' || result.target === targetDir, 'target matches scanned path');

0 commit comments

Comments
 (0)