prae-cli 0.7.1 → 0.9.1
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/lib/bin.js +3 -3
- package/lib/checkpoint-BWSuhZ5h.js +99 -0
- package/lib/{cli-mahLCjoD.js → cli-7yLG89gV.js} +210 -28
- package/lib/index.js +3 -3
- package/lib/{instructions-C104EUaE.js → instructions-Bg5puOen.js} +1 -1
- package/lib/{mcp-DDcejhwQ.js → mcp-doNYU-1C.js} +1 -1
- package/lib/ocsf-DhVGbBUw.js +211 -0
- package/lib/playground.js +92 -44
- package/lib/prae-baseline.prae.json +17 -9
- package/lib/{receipt-check-DrDE3Wwi.js → receipt-check-CD-W1wXs.js} +1 -1
- package/lib/secret-catcher.prae.json +7 -4
- package/lib/{src-Vnr0fcpK.js → src-CwBEFhww.js} +1 -1
- package/lib/src-D7g4lvaY.js +392 -0
- package/lib/src-d82lSKVQ.js +3 -0
- package/lib/{views-UODslKwu.js → views-CIg2ZNG0.js} +327 -63
- package/package.json +2 -2
- package/lib/src-C9L6NBvu.js +0 -3
- package/lib/src-Ciggx9ja.js +0 -242
- /package/lib/{src-Br1tGPtS.js → src-B25SHWcz.js} +0 -0
- /package/lib/{src-CQ0UmFUK.js → src-CBGZVvt7.js} +0 -0
- /package/lib/{src-CraUX64d.js → src-d4c_n6wd.js} +0 -0
- /package/lib/{test-run-DOaCKD1t.js → test-run-XNIRHKOu.js} +0 -0
|
@@ -1,50 +1,98 @@
|
|
|
1
1
|
//#region ../kernel/src/frameworks.ts
|
|
2
|
-
const FRAMEWORKS = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
2
|
+
const FRAMEWORKS = {
|
|
3
|
+
"owasp-llm-top-10-2026": {
|
|
4
|
+
name: "OWASP Top 10 for LLM Applications — 2026",
|
|
5
|
+
short: "OWASP LLM 2026",
|
|
6
|
+
controls: {
|
|
7
|
+
LLM01: {
|
|
8
|
+
name: "Prompt Injection",
|
|
9
|
+
summary: "Instructions in a prompt or in retrieved content alter what the model does."
|
|
10
|
+
},
|
|
11
|
+
LLM02: {
|
|
12
|
+
name: "Sensitive Information Disclosure",
|
|
13
|
+
summary: "Credentials, personal data or proprietary content reach the model or its output."
|
|
14
|
+
},
|
|
15
|
+
LLM03: {
|
|
16
|
+
name: "Excessive Agency",
|
|
17
|
+
summary: "The model can take actions, or holds permissions, beyond what its task needs."
|
|
18
|
+
},
|
|
19
|
+
LLM04: {
|
|
20
|
+
name: "Supply Chain",
|
|
21
|
+
summary: "A compromised model, dataset, plugin or dependency enters the application."
|
|
22
|
+
},
|
|
23
|
+
LLM05: {
|
|
24
|
+
name: "Data and Model Poisoning",
|
|
25
|
+
summary: "Training, fine-tuning or embedding data is manipulated to change behaviour."
|
|
26
|
+
},
|
|
27
|
+
LLM06: {
|
|
28
|
+
name: "Unbounded Consumption",
|
|
29
|
+
summary: "The application permits resource use without a limit, exhausting budget or service."
|
|
30
|
+
},
|
|
31
|
+
LLM07: {
|
|
32
|
+
name: "Misinformation",
|
|
33
|
+
summary: "The model produces false or misleading content that is acted on as if true."
|
|
34
|
+
},
|
|
35
|
+
LLM08: {
|
|
36
|
+
name: "Hidden Context Exposure",
|
|
37
|
+
summary: "System prompts, hidden instructions or internal context are revealed."
|
|
38
|
+
},
|
|
39
|
+
LLM09: {
|
|
40
|
+
name: "Vector and Embedding Weaknesses",
|
|
41
|
+
summary: "Retrieval stores are manipulated or leak across tenants and permissions."
|
|
42
|
+
},
|
|
43
|
+
LLM10: {
|
|
44
|
+
name: "Improper Output Handling",
|
|
45
|
+
summary: "Model output is passed to downstream systems without validation."
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"owasp-agentic-top-10-2026": {
|
|
50
|
+
name: "OWASP Top 10 for Agentic Applications — 2026",
|
|
51
|
+
short: "OWASP Agentic 2026",
|
|
52
|
+
controls: {
|
|
53
|
+
ASI01: {
|
|
54
|
+
name: "Agent Goal Hijack",
|
|
55
|
+
summary: "Untrusted input redirects what the agent is trying to do, turning its objectives against its owner."
|
|
56
|
+
},
|
|
57
|
+
ASI02: {
|
|
58
|
+
name: "Tool Misuse and Exploitation",
|
|
59
|
+
summary: "A legitimate tool the agent already holds is turned to an attacker's ends."
|
|
60
|
+
},
|
|
61
|
+
ASI03: {
|
|
62
|
+
name: "Identity and Privilege Abuse",
|
|
63
|
+
summary: "The agent's own authority, credentials or delegated access is inherited or escalated."
|
|
64
|
+
},
|
|
65
|
+
ASI04: {
|
|
66
|
+
name: "Agentic Supply Chain",
|
|
67
|
+
summary: "A poisoned tool, model, plugin, skill or dependency is trusted before the agent runs."
|
|
68
|
+
},
|
|
69
|
+
ASI05: {
|
|
70
|
+
name: "Unexpected Code Execution",
|
|
71
|
+
summary: "The agent's output reaches something that runs it: a shell, an interpreter, a parser."
|
|
72
|
+
},
|
|
73
|
+
ASI06: {
|
|
74
|
+
name: "Memory and Context Poisoning",
|
|
75
|
+
summary: "Corrupted memory or retrieved context persists across sessions and steers future reasoning."
|
|
76
|
+
},
|
|
77
|
+
ASI07: {
|
|
78
|
+
name: "Insecure Inter-Agent Communication",
|
|
79
|
+
summary: "One agent trusts another's messages by default, so a compromised agent can steer its peers."
|
|
80
|
+
},
|
|
81
|
+
ASI08: {
|
|
82
|
+
name: "Cascading Failures",
|
|
83
|
+
summary: "A single fault propagates across agents, tools and workflows into system-wide impact."
|
|
84
|
+
},
|
|
85
|
+
ASI09: {
|
|
86
|
+
name: "Human-Agent Trust Exploitation",
|
|
87
|
+
summary: "Persuasive or misleading agent output moves a person to an unsafe action or approval."
|
|
88
|
+
},
|
|
89
|
+
ASI10: {
|
|
90
|
+
name: "Rogue Agents",
|
|
91
|
+
summary: "A compromised, misaligned or drifting agent keeps operating in unintended ways."
|
|
92
|
+
}
|
|
45
93
|
}
|
|
46
94
|
}
|
|
47
|
-
}
|
|
95
|
+
};
|
|
48
96
|
/**
|
|
49
97
|
* Every framework control a rule cites, resolved to names.
|
|
50
98
|
*
|
|
@@ -802,6 +850,7 @@ const OBLIGATIONS = [
|
|
|
802
850
|
}
|
|
803
851
|
];
|
|
804
852
|
const OWASP = "owasp-llm-top-10-2026";
|
|
853
|
+
const AGENTIC = "owasp-agentic-top-10-2026";
|
|
805
854
|
/** Rules in the pack that cite one control of one framework. */
|
|
806
855
|
function citing(pack, framework, control) {
|
|
807
856
|
return (pack?.rules ?? []).filter((rule) => (rule.frameworks?.[framework] ?? []).includes(control));
|
|
@@ -819,32 +868,91 @@ const NOT_THIS_BOUNDARY = {
|
|
|
819
868
|
LLM07: "Whether an answer is true is not a property of a tool call.",
|
|
820
869
|
LLM08: "The assembled system prompt is sealed into the ledger as evidence of what the model was told; nothing here stops the model repeating it.",
|
|
821
870
|
LLM09: "Retrieval stores are upstream of the call the gate judges.",
|
|
822
|
-
LLM10: "What downstream code does with model output is that code's boundary, not this one's."
|
|
871
|
+
LLM10: "What downstream code does with model output is that code's boundary, not this one's.",
|
|
872
|
+
ASI04: "Where a tool, skill or plugin came from is settled before the agent runs. A rule on the skill tool (integrity, source) is how a pack refuses to trust one at load time; none in this pack does.",
|
|
873
|
+
ASI06: "Memory and retrieval stores are upstream of the call the gate judges. What the gate can do is seal what the agent was told (PRAE-ASM, PRAE-CTX) so a poisoned context is evidenced, never silent; this record holds no such seal.",
|
|
874
|
+
ASI07: "A message between agents is not a tool call; when it becomes one, it is judged like any other agent's call. The channel itself is outside this boundary.",
|
|
875
|
+
ASI09: "Whether a person was misled is not a property of a tool call. An ask verdict puts a human in the path and seals the outcome; nothing here judges the persuasion."
|
|
876
|
+
};
|
|
877
|
+
/**
|
|
878
|
+
* A risk this gate answers by *not* answering it: nothing here detects an
|
|
879
|
+
* injected instruction or a hijacked goal, and saying otherwise would be the
|
|
880
|
+
* claim a red team disproves first. What the gate does is bound what the
|
|
881
|
+
* subverted agent can execute — the cited controls of another risk doing
|
|
882
|
+
* their job. Said in those words, every time.
|
|
883
|
+
*/
|
|
884
|
+
const BOUNDED_BY = {
|
|
885
|
+
LLM01: {
|
|
886
|
+
framework: OWASP,
|
|
887
|
+
control: "LLM03"
|
|
888
|
+
},
|
|
889
|
+
ASI01: {
|
|
890
|
+
framework: AGENTIC,
|
|
891
|
+
control: "ASI02"
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
function bounded(data, risk, by) {
|
|
895
|
+
const bounding = citing(data.pack, by.framework, by.control);
|
|
896
|
+
const what = risk === "ASI01" ? "a hijacked goal" : "injected instructions";
|
|
897
|
+
const who = risk === "ASI01" ? "a hijacked agent" : "an injected instruction";
|
|
898
|
+
return {
|
|
899
|
+
state: "partial",
|
|
900
|
+
note: bounding.length === 0 ? `Not mitigated: this gate does not detect ${what}, and no ${by.control} control in this pack bounds what ${who} can execute.` : `Not mitigated: this gate does not detect ${what}. Bounded: ${bounding.length} ${by.control} control${bounding.length === 1 ? "" : "s"} (${bounding.map((r) => r.id).join(", ")}) decide what ${who} can execute.`
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Risks whose evidence is in the record rather than in a citing rule.
|
|
905
|
+
*
|
|
906
|
+
* ASI06: a poisoned context cannot be prevented here, but every change to what
|
|
907
|
+
* the agent was told is sealed, so it is evidenced. ASI10: a drifting agent's
|
|
908
|
+
* actions are judged like any other's; what the record shows is whether the
|
|
909
|
+
* gate refused any of them.
|
|
910
|
+
*/
|
|
911
|
+
const FROM_THE_RECORD = {
|
|
912
|
+
ASI06: (data) => {
|
|
913
|
+
const seals = data.entries.filter((e) => e.rule === "PRAE-ASM" || e.rule === "PRAE-CTX");
|
|
914
|
+
return seals.length === 0 ? void 0 : {
|
|
915
|
+
state: "partial",
|
|
916
|
+
note: `Evidenced, not prevented: ${seals.length} seal${seals.length === 1 ? "" : "s"} of what the agent was told (PRAE-ASM / PRAE-CTX) in this record; a poisoned context changes the hash and is answerable afterwards.`
|
|
917
|
+
};
|
|
918
|
+
},
|
|
919
|
+
ASI10: (data) => {
|
|
920
|
+
const refused = data.entries.filter((e) => e.verdict === "deny").length;
|
|
921
|
+
const armed = [
|
|
922
|
+
"ASI02",
|
|
923
|
+
"ASI03",
|
|
924
|
+
"ASI08"
|
|
925
|
+
].flatMap((c) => citing(data.pack, AGENTIC, c));
|
|
926
|
+
if (armed.length === 0) return void 0;
|
|
927
|
+
return {
|
|
928
|
+
state: refused > 0 ? "covered" : "partial",
|
|
929
|
+
note: refused > 0 ? `A drifting agent's actions are judged like any other's: ${armed.length} controls under ASI02/03/08 apply to every call, and ${refused} refusal${refused === 1 ? "" : "s"} in this record show them holding.` : `A drifting agent's actions are judged like any other's: ${armed.length} controls under ASI02/03/08 apply to every call; none has refused one in this record yet. Detecting drift itself is derived from the record, not a rule.`
|
|
930
|
+
};
|
|
931
|
+
}
|
|
823
932
|
};
|
|
824
|
-
function
|
|
825
|
-
const framework = FRAMEWORKS[
|
|
933
|
+
function frameworkRow(frameworkId, control) {
|
|
934
|
+
const framework = FRAMEWORKS[frameworkId];
|
|
826
935
|
const risk = framework?.controls[control];
|
|
827
936
|
const name = risk?.name ?? control;
|
|
828
937
|
return {
|
|
829
|
-
id: `${framework?.short ??
|
|
938
|
+
id: `${framework?.short ?? frameworkId} · ${control}`,
|
|
830
939
|
asks: `${name}. ${risk?.summary ?? ""}`.trim(),
|
|
831
940
|
evidence: (data) => {
|
|
832
941
|
if (data.pack === void 0) return {
|
|
833
942
|
state: "absent",
|
|
834
943
|
note: "No pack supplied to this view."
|
|
835
944
|
};
|
|
836
|
-
|
|
837
|
-
|
|
945
|
+
const by = BOUNDED_BY[control];
|
|
946
|
+
if (by !== void 0) return bounded(data, control, by);
|
|
947
|
+
const rules = citing(data.pack, frameworkId, control);
|
|
948
|
+
if (rules.length === 0) {
|
|
949
|
+
const derived = FROM_THE_RECORD[control]?.(data);
|
|
950
|
+
if (derived !== void 0) return derived;
|
|
838
951
|
return {
|
|
839
|
-
state: "
|
|
840
|
-
note:
|
|
952
|
+
state: "absent",
|
|
953
|
+
note: NOT_THIS_BOUNDARY[control] ?? "No rule in this pack cites this risk."
|
|
841
954
|
};
|
|
842
955
|
}
|
|
843
|
-
const rules = citing(data.pack, OWASP, control);
|
|
844
|
-
if (rules.length === 0) return {
|
|
845
|
-
state: "absent",
|
|
846
|
-
note: NOT_THIS_BOUNDARY[control] ?? "No rule in this pack cites this risk."
|
|
847
|
-
};
|
|
848
956
|
const ids = new Set(rules.map((rule) => rule.id));
|
|
849
957
|
const decisions = data.entries.filter((entry) => entry.rule !== void 0 && ids.has(entry.rule));
|
|
850
958
|
const listed = rules.map((rule) => rule.id).join(", ");
|
|
@@ -858,14 +966,170 @@ function owaspRow(control) {
|
|
|
858
966
|
}
|
|
859
967
|
};
|
|
860
968
|
}
|
|
861
|
-
const
|
|
969
|
+
const rowsOf = (frameworkId) => Object.keys(FRAMEWORKS[frameworkId]?.controls ?? {}).map((control) => frameworkRow(frameworkId, control));
|
|
970
|
+
const ISO_42001 = {
|
|
971
|
+
id: "iso-iec-42001-2023",
|
|
972
|
+
name: "ISO/IEC 42001:2023 — AI management system, Annex A"
|
|
973
|
+
};
|
|
974
|
+
const ISO_27001 = {
|
|
975
|
+
id: "iso-iec-27001-2022",
|
|
976
|
+
name: "ISO/IEC 27001:2022 — Annex A"
|
|
977
|
+
};
|
|
978
|
+
const isEvent = (e) => e.tool.startsWith("prae:") || e.tool === "system-prompt";
|
|
979
|
+
const decisionsOf = (data) => data.entries.filter((e) => !isEvent(e));
|
|
980
|
+
/** Rules in the pack whose `when` names a capability matching `test`. */
|
|
981
|
+
function rulesOn(pack, test) {
|
|
982
|
+
return (pack?.rules ?? []).filter((rule) => {
|
|
983
|
+
const cap = rule.when.capability;
|
|
984
|
+
return (cap === void 0 ? [] : typeof cap === "string" ? [cap] : cap).some(test);
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
/** The record itself: recorded, chained, and how much of it is signed. */
|
|
988
|
+
function recorded(data) {
|
|
989
|
+
const n = data.entries.length;
|
|
990
|
+
if (n === 0) return {
|
|
991
|
+
state: "partial",
|
|
992
|
+
note: "Recording is configured but nothing has been logged yet."
|
|
993
|
+
};
|
|
994
|
+
const signed = data.entries.filter((e) => e.sig !== void 0).length;
|
|
995
|
+
if (!data.verification.ok) return {
|
|
996
|
+
state: "partial",
|
|
997
|
+
note: `${n} rows recorded, but the chain does not verify: the log is present and its integrity is not.`
|
|
998
|
+
};
|
|
999
|
+
return {
|
|
1000
|
+
state: "covered",
|
|
1001
|
+
note: `${n} rows recorded, each hash-linked to the one before, chain intact${signed > 0 ? `, ${signed} of ${n} signed` : ", unsigned"} — an edited, removed or reordered row breaks it.`
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
/** Refusals and holds, recorded with their clause. */
|
|
1005
|
+
function monitored(data) {
|
|
1006
|
+
const refused = decisionsOf(data).filter((e) => e.verdict === "deny").length;
|
|
1007
|
+
const held = decisionsOf(data).filter((e) => e.verdict === "ask").length;
|
|
1008
|
+
return refused + held > 0 ? {
|
|
1009
|
+
state: "covered",
|
|
1010
|
+
note: `Every call is judged as it happens; this record holds ${refused} refusal${refused === 1 ? "" : "s"} and ${held} hold${held === 1 ? "" : "s"} for a human, each with the clause that produced it.`
|
|
1011
|
+
} : {
|
|
1012
|
+
state: "partial",
|
|
1013
|
+
note: "Every call is judged as it happens, but this record contains no refusal or hold yet, so the monitoring is unproven in practice."
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
const ISO_CONTROLS = [
|
|
1017
|
+
{
|
|
1018
|
+
id: "ISO/IEC 42001 · A.2.2",
|
|
1019
|
+
name: "AI policy",
|
|
1020
|
+
standard: ISO_42001,
|
|
1021
|
+
asks: "The organisation has a documented policy for developing or using AI systems.",
|
|
1022
|
+
evidence: (data) => data.pack === void 0 ? {
|
|
1023
|
+
state: "absent",
|
|
1024
|
+
note: "No pack supplied to this view."
|
|
1025
|
+
} : {
|
|
1026
|
+
state: "partial",
|
|
1027
|
+
note: `The executable part of an AI policy: ${data.pack.rules.length} rules declared as data and applied to every tool call. The policy document and its approval are the organisation's.`
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
id: "ISO/IEC 42001 · A.6.2.6",
|
|
1032
|
+
name: "AI system operation and monitoring",
|
|
1033
|
+
standard: ISO_42001,
|
|
1034
|
+
asks: "The AI system is monitored while it operates, and what is found is acted on.",
|
|
1035
|
+
evidence: monitored
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
id: "ISO/IEC 42001 · A.6.2.8",
|
|
1039
|
+
name: "Recording of event logs",
|
|
1040
|
+
standard: ISO_42001,
|
|
1041
|
+
asks: "Event logs are kept while the AI system is in use.",
|
|
1042
|
+
evidence: recorded
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
id: "ISO/IEC 42001 · A.9.4",
|
|
1046
|
+
name: "Intended use of the AI system",
|
|
1047
|
+
standard: ISO_42001,
|
|
1048
|
+
asks: "The AI system is used only for its intended uses.",
|
|
1049
|
+
evidence: (data) => {
|
|
1050
|
+
if (data.pack === void 0) return {
|
|
1051
|
+
state: "absent",
|
|
1052
|
+
note: "No pack supplied to this view."
|
|
1053
|
+
};
|
|
1054
|
+
const refused = decisionsOf(data).filter((e) => e.verdict === "deny").length;
|
|
1055
|
+
return refused > 0 ? {
|
|
1056
|
+
state: "covered",
|
|
1057
|
+
note: `Intended use is enforced as scope: ${refused} action${refused === 1 ? "" : "s"} outside it refused before execution in this record.`
|
|
1058
|
+
} : {
|
|
1059
|
+
state: "partial",
|
|
1060
|
+
note: "Intended use is enforced as scope by the pack; nothing outside it has been attempted in this record yet."
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
{
|
|
1065
|
+
id: "ISO/IEC 27001 · A.8.3",
|
|
1066
|
+
name: "Information access restriction",
|
|
1067
|
+
standard: ISO_27001,
|
|
1068
|
+
asks: "Access to information is restricted according to the access-control policy.",
|
|
1069
|
+
evidence: (data) => {
|
|
1070
|
+
const rules = rulesOn(data.pack, (c) => c.startsWith("fs:"));
|
|
1071
|
+
if (rules.length === 0) return {
|
|
1072
|
+
state: "absent",
|
|
1073
|
+
note: "No rule in this pack restricts file access."
|
|
1074
|
+
};
|
|
1075
|
+
const refused = decisionsOf(data).filter((e) => e.verdict === "deny" && e.capability?.startsWith("fs:")).length;
|
|
1076
|
+
return refused > 0 ? {
|
|
1077
|
+
state: "covered",
|
|
1078
|
+
note: `${rules.length} file-access rules restrict what the agent may read and write; ${refused} access${refused === 1 ? "" : "es"} refused in this record. Restriction is per agent, not per human.`
|
|
1079
|
+
} : {
|
|
1080
|
+
state: "partial",
|
|
1081
|
+
note: `${rules.length} file-access rules restrict what the agent may read and write; none has refused an access in this record yet.`
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
},
|
|
1085
|
+
{
|
|
1086
|
+
id: "ISO/IEC 27001 · A.8.12",
|
|
1087
|
+
name: "Data leakage prevention",
|
|
1088
|
+
standard: ISO_27001,
|
|
1089
|
+
asks: "Leakage of sensitive information is prevented where it is processed or sent.",
|
|
1090
|
+
evidence: (data) => {
|
|
1091
|
+
const rules = [...rulesOn(data.pack, (c) => c === "net:fetch"), ...(data.pack?.rules ?? []).filter((r) => r.when.secrets !== void 0)];
|
|
1092
|
+
if (rules.length === 0) return {
|
|
1093
|
+
state: "absent",
|
|
1094
|
+
note: "No rule in this pack governs egress or credentials."
|
|
1095
|
+
};
|
|
1096
|
+
const stopped = decisionsOf(data).filter((e) => e.verdict === "deny" && (e.capability === "net:fetch" || e.secrets !== void 0 || e.phase === "output")).length;
|
|
1097
|
+
return stopped > 0 ? {
|
|
1098
|
+
state: "covered",
|
|
1099
|
+
note: `${new Set(rules.map((r) => r.id)).size} egress and credential rules; ${stopped} send${stopped === 1 ? "" : "s"} or credential read${stopped === 1 ? "" : "s"} stopped in this record before the data left.`
|
|
1100
|
+
} : {
|
|
1101
|
+
state: "partial",
|
|
1102
|
+
note: `${new Set(rules.map((r) => r.id)).size} egress and credential rules in force; none has stopped anything in this record yet.`
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
id: "ISO/IEC 27001 · A.8.15",
|
|
1108
|
+
name: "Logging",
|
|
1109
|
+
standard: ISO_27001,
|
|
1110
|
+
asks: "Activities, exceptions and other relevant events are logged, and the logs are protected.",
|
|
1111
|
+
evidence: recorded
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
id: "ISO/IEC 27001 · A.8.16",
|
|
1115
|
+
name: "Monitoring activities",
|
|
1116
|
+
standard: ISO_27001,
|
|
1117
|
+
asks: "Systems are monitored for anomalous behaviour, and potential incidents are evaluated.",
|
|
1118
|
+
evidence: monitored
|
|
1119
|
+
}
|
|
1120
|
+
];
|
|
862
1121
|
/**
|
|
863
|
-
* The obligations first, then the
|
|
864
|
-
* on purpose: an auditor reads down one list and finds the
|
|
865
|
-
* the ledger evidences and the application risks the pack's
|
|
866
|
-
* each stated in its framework's own words.
|
|
1122
|
+
* The obligations first, then the risks framework by framework. Two kinds of
|
|
1123
|
+
* row in one table on purpose: an auditor reads down one list and finds the
|
|
1124
|
+
* audit obligations the ledger evidences and the application risks the pack's
|
|
1125
|
+
* rules address, each stated in its framework's own words.
|
|
867
1126
|
*/
|
|
868
|
-
const CONTROLS = [
|
|
1127
|
+
const CONTROLS = [
|
|
1128
|
+
...OBLIGATIONS,
|
|
1129
|
+
...rowsOf(OWASP),
|
|
1130
|
+
...rowsOf(AGENTIC),
|
|
1131
|
+
...ISO_CONTROLS
|
|
1132
|
+
];
|
|
869
1133
|
|
|
870
1134
|
//#endregion
|
|
871
1135
|
//#region src/console/views.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prae-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Operator policy for agent harnesses: validate packs, explain a decision, test a pack against security invariants, verify a decision log, and provision a governed DSH profile.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"tsdown": "^0.15.6",
|
|
41
41
|
"typescript": "^5.9.2",
|
|
42
42
|
"vitest": "^3.2.4",
|
|
43
|
+
"@prae/controls": "0.1.0",
|
|
43
44
|
"@prae/extract": "0.1.0",
|
|
44
45
|
"@prae/inspect": "0.1.0",
|
|
45
46
|
"@prae/instructions": "0.1.0",
|
|
46
47
|
"@prae/kernel": "0.1.0",
|
|
47
48
|
"@prae/ledger": "0.1.0",
|
|
48
|
-
"@prae/controls": "0.1.0",
|
|
49
49
|
"@prae/tokens": "0.1.0"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
package/lib/src-C9L6NBvu.js
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { a as generateKeypair, c as verifyReceipt, d as canonical, f as chain, i as fingerprint, l as verifySignature, m as seal, n as readEntries, o as makeReceipt, p as hashEntry, r as verifyEntries, s as signEntry, t as Ledger, u as GENESIS } from "./src-Ciggx9ja.js";
|
|
2
|
-
|
|
3
|
-
export { GENESIS, Ledger, canonical, chain, fingerprint, generateKeypair, hashEntry, makeReceipt, readEntries, seal, signEntry, verifyEntries, verifyReceipt, verifySignature };
|