diff --git a/.clinerules b/.clinerules index 9c8a9358..4e4bd775 100644 --- a/.clinerules +++ b/.clinerules @@ -114,7 +114,7 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, - LLMConfig -> #llm-client via chatCompletion - #llm-client -> LLMProvider via fetch - LLMProvider -> #llm-client via response -- … and 183 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood +- … and 185 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood ### Features (filter with `--feature`) @@ -123,11 +123,11 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, ### Model Stats -885 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 130 mitigations, 3 actors, 1 entitlements, 203 flows, 2 features +891 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 131 mitigations, 3 actors, 1 entitlements, 205 flows, 2 features ### Block Freshness -- `annotation_hash`: `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293` +- `annotation_hash`: `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b` Every MCP response carries this same hash. If it differs from the one above, this block predates the current annotations — trust the tool, and run `guardlink sync`. diff --git a/.cursor/rules/guardlink.mdc b/.cursor/rules/guardlink.mdc index 7ab21058..0c31265d 100644 --- a/.cursor/rules/guardlink.mdc +++ b/.cursor/rules/guardlink.mdc @@ -119,7 +119,7 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, - LLMConfig -> #llm-client via chatCompletion - #llm-client -> LLMProvider via fetch - LLMProvider -> #llm-client via response -- … and 183 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood +- … and 185 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood ### Features (filter with `--feature`) @@ -128,11 +128,11 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, ### Model Stats -885 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 130 mitigations, 3 actors, 1 entitlements, 203 flows, 2 features +891 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 131 mitigations, 3 actors, 1 entitlements, 205 flows, 2 features ### Block Freshness -- `annotation_hash`: `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293` +- `annotation_hash`: `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b` Every MCP response carries this same hash. If it differs from the one above, this block predates the current annotations — trust the tool, and run `guardlink sync`. diff --git a/.gemini/GEMINI.md b/.gemini/GEMINI.md index 2e23db1a..e0889084 100644 --- a/.gemini/GEMINI.md +++ b/.gemini/GEMINI.md @@ -170,7 +170,7 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, - LLMConfig -> #llm-client via chatCompletion - #llm-client -> LLMProvider via fetch - LLMProvider -> #llm-client via response -- … and 183 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood +- … and 185 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood ### Features (filter with `--feature`) @@ -179,11 +179,11 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, ### Model Stats -885 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 130 mitigations, 3 actors, 1 entitlements, 203 flows, 2 features +891 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 131 mitigations, 3 actors, 1 entitlements, 205 flows, 2 features ### Block Freshness -- `annotation_hash`: `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293` +- `annotation_hash`: `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b` Every MCP response carries this same hash. If it differs from the one above, this block predates the current annotations — trust the tool, and run `guardlink sync`. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2e23db1a..e0889084 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -170,7 +170,7 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, - LLMConfig -> #llm-client via chatCompletion - #llm-client -> LLMProvider via fetch - LLMProvider -> #llm-client via response -- … and 183 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood +- … and 185 more — `guardlink_lookup("flows into X")` for one asset, or `guardlink_graph(from: X)` for a neighbourhood ### Features (filter with `--feature`) @@ -179,11 +179,11 @@ _Full records with descriptions and locations: `guardlink_lookup("asset ")`, ### Model Stats -885 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 130 mitigations, 3 actors, 1 entitlements, 203 flows, 2 features +891 annotations, 20 assets, 16 threats, 14 controls, 127 exposures, 0 confirmed, 131 mitigations, 3 actors, 1 entitlements, 205 flows, 2 features ### Block Freshness -- `annotation_hash`: `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293` +- `annotation_hash`: `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b` Every MCP response carries this same hash. If it differs from the one above, this block predates the current annotations — trust the tool, and run `guardlink sync`. diff --git a/.guardlink/README.md b/.guardlink/README.md index 0ad063d9..334007c6 100644 --- a/.guardlink/README.md +++ b/.guardlink/README.md @@ -11,8 +11,8 @@ accepted. This file is generated. Run `guardlink sync` to refresh it; do not edit it by hand. -Current model: 885 annotations · 20 assets · 16 threats · 14 controls · 127 exposures · 203 flows -Content hash: `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293` — identical hash means identical model. +Current model: 891 annotations · 20 assets · 16 threats · 14 controls · 127 exposures · 205 flows +Content hash: `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b` — identical hash means identical model. --- diff --git a/.guardlink/graph/MANIFEST.json b/.guardlink/graph/MANIFEST.json index ec5fdb0c..f6b38ca2 100644 --- a/.guardlink/graph/MANIFEST.json +++ b/.guardlink/graph/MANIFEST.json @@ -1,12 +1,12 @@ { "schema_version": 2, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "generator": "guardlink@2.1.0", "artifacts": [ { "path": ".guardlink/graph/threat-graph.mmd", "bytes": 12296, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 10687, @@ -15,18 +15,18 @@ }, { "path": ".guardlink/graph/dataflow.mmd", - "bytes": 15487, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "bytes": 15590, + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { - "text_size": 13397, - "edges": 193 + "text_size": 13496, + "edges": 195 } }, { "path": ".guardlink/graph/attack-surface.mmd", "bytes": 6630, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 4957, @@ -36,7 +36,7 @@ { "path": ".guardlink/graph/by-feature/dashboard.mmd", "bytes": 2301, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 813, @@ -46,7 +46,7 @@ { "path": ".guardlink/graph/by-feature/mcp-integration.mmd", "bytes": 2749, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1235, @@ -56,7 +56,7 @@ { "path": ".guardlink/graph/by-asset/agent-launcher.threats.mmd", "bytes": 2270, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1437, @@ -66,7 +66,7 @@ { "path": ".guardlink/graph/by-asset/agent-launcher.flows.mmd", "bytes": 2258, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1404, @@ -76,7 +76,7 @@ { "path": ".guardlink/graph/by-asset/blame.threats.mmd", "bytes": 2211, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1477, @@ -86,7 +86,7 @@ { "path": ".guardlink/graph/by-asset/blame.flows.mmd", "bytes": 1621, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 803, @@ -96,7 +96,7 @@ { "path": ".guardlink/graph/by-asset/cli.threats.mmd", "bytes": 2185, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1373, @@ -106,7 +106,7 @@ { "path": ".guardlink/graph/by-asset/cli.flows.mmd", "bytes": 1930, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1098, @@ -116,7 +116,7 @@ { "path": ".guardlink/graph/by-asset/codegraph.threats.mmd", "bytes": 1853, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1125, @@ -126,7 +126,7 @@ { "path": ".guardlink/graph/by-asset/codegraph.flows.mmd", "bytes": 2363, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1517, @@ -136,7 +136,7 @@ { "path": ".guardlink/graph/by-asset/dashboard.threats.mmd", "bytes": 2326, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1586, @@ -146,7 +146,7 @@ { "path": ".guardlink/graph/by-asset/dashboard.flows.mmd", "bytes": 2011, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1167, @@ -156,7 +156,7 @@ { "path": ".guardlink/graph/by-asset/diff.threats.mmd", "bytes": 1764, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1044, @@ -166,7 +166,7 @@ { "path": ".guardlink/graph/by-asset/diff.flows.mmd", "bytes": 1559, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 751, @@ -176,7 +176,7 @@ { "path": ".guardlink/graph/by-asset/estate-view.threats.mmd", "bytes": 1555, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 827, @@ -186,7 +186,7 @@ { "path": ".guardlink/graph/by-asset/estate-view.flows.mmd", "bytes": 1915, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1073, @@ -196,7 +196,7 @@ { "path": ".guardlink/graph/by-asset/gate.threats.mmd", "bytes": 1274, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 566, @@ -206,7 +206,7 @@ { "path": ".guardlink/graph/by-asset/gate.flows.mmd", "bytes": 1831, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1013, @@ -216,7 +216,7 @@ { "path": ".guardlink/graph/by-asset/init.threats.mmd", "bytes": 1683, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 967, @@ -226,7 +226,7 @@ { "path": ".guardlink/graph/by-asset/init.flows.mmd", "bytes": 2103, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1263, @@ -236,7 +236,7 @@ { "path": ".guardlink/graph/by-asset/llm-client.threats.mmd", "bytes": 1876, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1056, @@ -246,7 +246,7 @@ { "path": ".guardlink/graph/by-asset/llm-client.flows.mmd", "bytes": 2191, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1342, @@ -256,7 +256,7 @@ { "path": ".guardlink/graph/by-asset/mcp.threats.mmd", "bytes": 1807, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1003, @@ -266,7 +266,7 @@ { "path": ".guardlink/graph/by-asset/mcp.flows.mmd", "bytes": 1883, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1057, @@ -276,7 +276,7 @@ { "path": ".guardlink/graph/by-asset/merge-engine.threats.mmd", "bytes": 1485, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 755, @@ -286,7 +286,7 @@ { "path": ".guardlink/graph/by-asset/merge-engine.flows.mmd", "bytes": 2157, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1299, @@ -296,7 +296,7 @@ { "path": ".guardlink/graph/by-asset/parser.threats.mmd", "bytes": 1716, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 910, @@ -306,7 +306,7 @@ { "path": ".guardlink/graph/by-asset/parser.flows.mmd", "bytes": 2142, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1302, @@ -316,7 +316,7 @@ { "path": ".guardlink/graph/by-asset/report.threats.mmd", "bytes": 1222, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 510, @@ -325,18 +325,18 @@ }, { "path": ".guardlink/graph/by-asset/report.flows.mmd", - "bytes": 1225, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "bytes": 1275, + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { - "text_size": 431, - "edges": 4 + "text_size": 479, + "edges": 5 } }, { "path": ".guardlink/graph/by-asset/report-metadata.threats.mmd", "bytes": 1323, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 593, @@ -346,7 +346,7 @@ { "path": ".guardlink/graph/by-asset/report-metadata.flows.mmd", "bytes": 1943, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1105, @@ -356,7 +356,7 @@ { "path": ".guardlink/graph/by-asset/sarif.threats.mmd", "bytes": 1350, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 638, @@ -366,7 +366,7 @@ { "path": ".guardlink/graph/by-asset/sarif.flows.mmd", "bytes": 1396, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 596, @@ -376,7 +376,7 @@ { "path": ".guardlink/graph/by-asset/suggest.threats.mmd", "bytes": 1582, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 860, @@ -386,7 +386,7 @@ { "path": ".guardlink/graph/by-asset/suggest.flows.mmd", "bytes": 2143, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1299, @@ -396,7 +396,7 @@ { "path": ".guardlink/graph/by-asset/tui.threats.mmd", "bytes": 2073, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1349, @@ -406,7 +406,7 @@ { "path": ".guardlink/graph/by-asset/tui.flows.mmd", "bytes": 2052, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1218, @@ -416,7 +416,7 @@ { "path": ".guardlink/graph/by-asset/workspace-config.threats.mmd", "bytes": 1278, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 546, @@ -426,7 +426,7 @@ { "path": ".guardlink/graph/by-asset/workspace-link.flows.mmd", "bytes": 1972, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1122, @@ -436,7 +436,7 @@ { "path": ".guardlink/graph/by-boundary/agent-boundary.mmd", "bytes": 2227, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1404, @@ -446,7 +446,7 @@ { "path": ".guardlink/graph/by-boundary/llm-api-boundary.mmd", "bytes": 2169, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1342, @@ -456,7 +456,7 @@ { "path": ".guardlink/graph/by-boundary/nvd-api-boundary.mmd", "bytes": 2156, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1342, @@ -466,7 +466,7 @@ { "path": ".guardlink/graph/by-boundary/cli-input-boundary.mmd", "bytes": 2241, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1410, @@ -476,7 +476,7 @@ { "path": ".guardlink/graph/by-boundary/codegraph-boundary.mmd", "bytes": 2397, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1517, @@ -486,7 +486,7 @@ { "path": ".guardlink/graph/by-boundary/git-boundary.mmd", "bytes": 2046, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1230, @@ -496,7 +496,7 @@ { "path": ".guardlink/graph/by-boundary/mcp-boundary.mmd", "bytes": 2227, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1413, @@ -506,7 +506,7 @@ { "path": ".guardlink/graph/by-boundary/mcp-tool-boundary.mmd", "bytes": 2241, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1413, @@ -516,7 +516,7 @@ { "path": ".guardlink/graph/by-boundary/fs-boundary.mmd", "bytes": 2260, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1421, @@ -526,7 +526,7 @@ { "path": ".guardlink/graph/by-boundary/tui-input-boundary.mmd", "bytes": 2028, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "renderable": true, "render": { "text_size": 1212, @@ -535,8 +535,8 @@ }, { "path": ".guardlink/model.json", - "bytes": 281922, - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293" + "bytes": 283866, + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b" } ] } diff --git a/.guardlink/graph/attack-surface.mmd b/.guardlink/graph/attack-surface.mmd index 4a3acae9..e368440d 100644 --- a/.guardlink/graph/attack-surface.mmd +++ b/.guardlink/graph/attack-surface.mmd @@ -1,6 +1,6 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: attack-surface.mmd -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/agent-launcher.flows.mmd b/.guardlink/graph/by-asset/agent-launcher.flows.mmd index 45c0597f..35c1c664 100644 --- a/.guardlink/graph/by-asset/agent-launcher.flows.mmd +++ b/.guardlink/graph/by-asset/agent-launcher.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/agent-launcher.flows.mmd %% scope: PARTIAL — #agent-launcher and its flow neighbourhood, grown until the drawing stopped fitting — 20 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/agent-launcher.threats.mmd b/.guardlink/graph/by-asset/agent-launcher.threats.mmd index f2c0b3cf..ae57e87b 100644 --- a/.guardlink/graph/by-asset/agent-launcher.threats.mmd +++ b/.guardlink/graph/by-asset/agent-launcher.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/agent-launcher.threats.mmd %% scope: PARTIAL — #agent-launcher only — its own threats and controls, narrowed to high and critical (8 lower-severity claim(s) omitted to keep it readable) -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/blame.flows.mmd b/.guardlink/graph/by-asset/blame.flows.mmd index 39d38a5e..89ec95cb 100644 --- a/.guardlink/graph/by-asset/blame.flows.mmd +++ b/.guardlink/graph/by-asset/blame.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/blame.flows.mmd %% scope: PARTIAL — #blame and its flow neighbourhood, grown until the drawing stopped fitting — 26 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/blame.threats.mmd b/.guardlink/graph/by-asset/blame.threats.mmd index b72f8029..bd856785 100644 --- a/.guardlink/graph/by-asset/blame.threats.mmd +++ b/.guardlink/graph/by-asset/blame.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/blame.threats.mmd %% scope: PARTIAL — #blame only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/cli.flows.mmd b/.guardlink/graph/by-asset/cli.flows.mmd index 17512324..0a2917ef 100644 --- a/.guardlink/graph/by-asset/cli.flows.mmd +++ b/.guardlink/graph/by-asset/cli.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/cli.flows.mmd %% scope: PARTIAL — #cli and its flow neighbourhood, grown until the drawing stopped fitting — 25 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/cli.threats.mmd b/.guardlink/graph/by-asset/cli.threats.mmd index dce93183..730dd4d8 100644 --- a/.guardlink/graph/by-asset/cli.threats.mmd +++ b/.guardlink/graph/by-asset/cli.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/cli.threats.mmd %% scope: PARTIAL — #cli only — its own threats and controls, narrowed to high and critical (13 lower-severity claim(s) omitted to keep it readable) -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/codegraph.flows.mmd b/.guardlink/graph/by-asset/codegraph.flows.mmd index 86853e8a..a290d81b 100644 --- a/.guardlink/graph/by-asset/codegraph.flows.mmd +++ b/.guardlink/graph/by-asset/codegraph.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/codegraph.flows.mmd %% scope: PARTIAL — #codegraph and its flow neighbourhood, grown until the drawing stopped fitting — 36 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/codegraph.threats.mmd b/.guardlink/graph/by-asset/codegraph.threats.mmd index 01d493dd..9755bb5c 100644 --- a/.guardlink/graph/by-asset/codegraph.threats.mmd +++ b/.guardlink/graph/by-asset/codegraph.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/codegraph.threats.mmd %% scope: PARTIAL — #codegraph only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/dashboard.flows.mmd b/.guardlink/graph/by-asset/dashboard.flows.mmd index ab5d5090..14beae8c 100644 --- a/.guardlink/graph/by-asset/dashboard.flows.mmd +++ b/.guardlink/graph/by-asset/dashboard.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/dashboard.flows.mmd %% scope: PARTIAL — #dashboard and its flow neighbourhood, grown until the drawing stopped fitting — 12 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/dashboard.threats.mmd b/.guardlink/graph/by-asset/dashboard.threats.mmd index f4b53ebc..7b5cd884 100644 --- a/.guardlink/graph/by-asset/dashboard.threats.mmd +++ b/.guardlink/graph/by-asset/dashboard.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/dashboard.threats.mmd %% scope: PARTIAL — #dashboard only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/diff.flows.mmd b/.guardlink/graph/by-asset/diff.flows.mmd index df356ac4..02b71c08 100644 --- a/.guardlink/graph/by-asset/diff.flows.mmd +++ b/.guardlink/graph/by-asset/diff.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/diff.flows.mmd %% scope: PARTIAL — #diff and its flow neighbourhood, grown until the drawing stopped fitting — 12 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/diff.threats.mmd b/.guardlink/graph/by-asset/diff.threats.mmd index ca39cc85..9163a703 100644 --- a/.guardlink/graph/by-asset/diff.threats.mmd +++ b/.guardlink/graph/by-asset/diff.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/diff.threats.mmd %% scope: PARTIAL — #diff only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/estate-view.flows.mmd b/.guardlink/graph/by-asset/estate-view.flows.mmd index 3cff3de8..7de930f8 100644 --- a/.guardlink/graph/by-asset/estate-view.flows.mmd +++ b/.guardlink/graph/by-asset/estate-view.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/estate-view.flows.mmd %% scope: PARTIAL — #estate-view and its flow neighbourhood, grown until the drawing stopped fitting — 23 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/estate-view.threats.mmd b/.guardlink/graph/by-asset/estate-view.threats.mmd index c2e60012..4c9757c0 100644 --- a/.guardlink/graph/by-asset/estate-view.threats.mmd +++ b/.guardlink/graph/by-asset/estate-view.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/estate-view.threats.mmd %% scope: PARTIAL — #estate-view only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/gate.flows.mmd b/.guardlink/graph/by-asset/gate.flows.mmd index 472bbaa3..f2446bcb 100644 --- a/.guardlink/graph/by-asset/gate.flows.mmd +++ b/.guardlink/graph/by-asset/gate.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/gate.flows.mmd %% scope: PARTIAL — #gate and its flow neighbourhood, grown until the drawing stopped fitting — 24 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/gate.threats.mmd b/.guardlink/graph/by-asset/gate.threats.mmd index 0de1f2a9..64851c38 100644 --- a/.guardlink/graph/by-asset/gate.threats.mmd +++ b/.guardlink/graph/by-asset/gate.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/gate.threats.mmd %% scope: PARTIAL — #gate only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/init.flows.mmd b/.guardlink/graph/by-asset/init.flows.mmd index d17d970f..12eac32a 100644 --- a/.guardlink/graph/by-asset/init.flows.mmd +++ b/.guardlink/graph/by-asset/init.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/init.flows.mmd %% scope: PARTIAL — #init and its flow neighbourhood, grown until the drawing stopped fitting — 28 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/init.threats.mmd b/.guardlink/graph/by-asset/init.threats.mmd index 440d345f..8a34db6b 100644 --- a/.guardlink/graph/by-asset/init.threats.mmd +++ b/.guardlink/graph/by-asset/init.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/init.threats.mmd %% scope: PARTIAL — #init only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/llm-client.flows.mmd b/.guardlink/graph/by-asset/llm-client.flows.mmd index 73ac5ab8..74aab615 100644 --- a/.guardlink/graph/by-asset/llm-client.flows.mmd +++ b/.guardlink/graph/by-asset/llm-client.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/llm-client.flows.mmd %% scope: PARTIAL — #llm-client and its flow neighbourhood, grown until the drawing stopped fitting — 13 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/llm-client.threats.mmd b/.guardlink/graph/by-asset/llm-client.threats.mmd index 6952f547..62dc69d0 100644 --- a/.guardlink/graph/by-asset/llm-client.threats.mmd +++ b/.guardlink/graph/by-asset/llm-client.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/llm-client.threats.mmd %% scope: PARTIAL — #llm-client only — its own threats and controls, narrowed to high and critical (13 lower-severity claim(s) omitted to keep it readable) -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/mcp.flows.mmd b/.guardlink/graph/by-asset/mcp.flows.mmd index c1f9e037..9118434b 100644 --- a/.guardlink/graph/by-asset/mcp.flows.mmd +++ b/.guardlink/graph/by-asset/mcp.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/mcp.flows.mmd %% scope: PARTIAL — #mcp and its flow neighbourhood, grown until the drawing stopped fitting — 20 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/mcp.threats.mmd b/.guardlink/graph/by-asset/mcp.threats.mmd index 85848b26..b38393f5 100644 --- a/.guardlink/graph/by-asset/mcp.threats.mmd +++ b/.guardlink/graph/by-asset/mcp.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/mcp.threats.mmd %% scope: PARTIAL — #mcp only — its own threats and controls, narrowed to high and critical (12 lower-severity claim(s) omitted to keep it readable) -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/merge-engine.flows.mmd b/.guardlink/graph/by-asset/merge-engine.flows.mmd index 93100884..11bf353e 100644 --- a/.guardlink/graph/by-asset/merge-engine.flows.mmd +++ b/.guardlink/graph/by-asset/merge-engine.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/merge-engine.flows.mmd %% scope: PARTIAL — #merge-engine and its flow neighbourhood, grown until the drawing stopped fitting — 34 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/merge-engine.threats.mmd b/.guardlink/graph/by-asset/merge-engine.threats.mmd index a01d1f13..125075a6 100644 --- a/.guardlink/graph/by-asset/merge-engine.threats.mmd +++ b/.guardlink/graph/by-asset/merge-engine.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/merge-engine.threats.mmd %% scope: PARTIAL — #merge-engine only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/parser.flows.mmd b/.guardlink/graph/by-asset/parser.flows.mmd index 39f06c08..13415dcf 100644 --- a/.guardlink/graph/by-asset/parser.flows.mmd +++ b/.guardlink/graph/by-asset/parser.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/parser.flows.mmd %% scope: PARTIAL — #parser and its flow neighbourhood, grown until the drawing stopped fitting — 13 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/parser.threats.mmd b/.guardlink/graph/by-asset/parser.threats.mmd index d40e8e78..840f2e4e 100644 --- a/.guardlink/graph/by-asset/parser.threats.mmd +++ b/.guardlink/graph/by-asset/parser.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/parser.threats.mmd %% scope: PARTIAL — #parser only — its own threats and controls, narrowed to high and critical (31 lower-severity claim(s) omitted to keep it readable) -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/report-metadata.flows.mmd b/.guardlink/graph/by-asset/report-metadata.flows.mmd index da770225..d026da44 100644 --- a/.guardlink/graph/by-asset/report-metadata.flows.mmd +++ b/.guardlink/graph/by-asset/report-metadata.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/report-metadata.flows.mmd %% scope: PARTIAL — #report-metadata and its flow neighbourhood, grown until the drawing stopped fitting — 24 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/report-metadata.threats.mmd b/.guardlink/graph/by-asset/report-metadata.threats.mmd index 23becd87..f23534c1 100644 --- a/.guardlink/graph/by-asset/report-metadata.threats.mmd +++ b/.guardlink/graph/by-asset/report-metadata.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/report-metadata.threats.mmd %% scope: PARTIAL — #report-metadata only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/report.flows.mmd b/.guardlink/graph/by-asset/report.flows.mmd index 3959cea4..3a1b944c 100644 --- a/.guardlink/graph/by-asset/report.flows.mmd +++ b/.guardlink/graph/by-asset/report.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/report.flows.mmd %% scope: PARTIAL — #report and its flow neighbourhood, grown until the drawing stopped fitting — 11 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If @@ -11,10 +11,11 @@ %% unrelated to the diagram, so they are reported at emission time, not stored. %%{init: {"flowchart": {"nodeSpacing": 44, "rankSpacing": 58, "curve": "basis", "htmlLabels": false}}}%% graph LR - featurename["🧩 FeatureName"] - report["🧩 GuardLink.Report"] threatmodel["🧩 ThreatModel"] + report["🧩 GuardLink.Report"] + featurename["🧩 FeatureName"] markdown["🧩 Markdown"] + threatmodel -- "📡 summarizeReach" --> report featurename -- "📡 filtered_by_features" --> report threatmodel -- "📡 generateReport" --> report report -- "📡 return" --> markdown diff --git a/.guardlink/graph/by-asset/report.threats.mmd b/.guardlink/graph/by-asset/report.threats.mmd index c13f8534..bfdebf5a 100644 --- a/.guardlink/graph/by-asset/report.threats.mmd +++ b/.guardlink/graph/by-asset/report.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/report.threats.mmd %% scope: PARTIAL — #report only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/sarif.flows.mmd b/.guardlink/graph/by-asset/sarif.flows.mmd index a131c53a..ada5d076 100644 --- a/.guardlink/graph/by-asset/sarif.flows.mmd +++ b/.guardlink/graph/by-asset/sarif.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/sarif.flows.mmd %% scope: PARTIAL — #sarif and its flow neighbourhood, grown until the drawing stopped fitting — 11 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/sarif.threats.mmd b/.guardlink/graph/by-asset/sarif.threats.mmd index caf31dd6..18d4d80b 100644 --- a/.guardlink/graph/by-asset/sarif.threats.mmd +++ b/.guardlink/graph/by-asset/sarif.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/sarif.threats.mmd %% scope: PARTIAL — #sarif only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/suggest.flows.mmd b/.guardlink/graph/by-asset/suggest.flows.mmd index 35fbf40f..26f8bbd5 100644 --- a/.guardlink/graph/by-asset/suggest.flows.mmd +++ b/.guardlink/graph/by-asset/suggest.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/suggest.flows.mmd %% scope: PARTIAL — #suggest and its flow neighbourhood, grown until the drawing stopped fitting — 14 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/suggest.threats.mmd b/.guardlink/graph/by-asset/suggest.threats.mmd index cebce3a4..03e92476 100644 --- a/.guardlink/graph/by-asset/suggest.threats.mmd +++ b/.guardlink/graph/by-asset/suggest.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/suggest.threats.mmd %% scope: PARTIAL — #suggest only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/tui.flows.mmd b/.guardlink/graph/by-asset/tui.flows.mmd index 8d836565..21f836e4 100644 --- a/.guardlink/graph/by-asset/tui.flows.mmd +++ b/.guardlink/graph/by-asset/tui.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/tui.flows.mmd %% scope: PARTIAL — #tui and its flow neighbourhood, grown until the drawing stopped fitting — 24 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/tui.threats.mmd b/.guardlink/graph/by-asset/tui.threats.mmd index 201016ac..e64cb716 100644 --- a/.guardlink/graph/by-asset/tui.threats.mmd +++ b/.guardlink/graph/by-asset/tui.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/tui.threats.mmd %% scope: PARTIAL — #tui only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/workspace-config.threats.mmd b/.guardlink/graph/by-asset/workspace-config.threats.mmd index 8f49c714..c9ad0d8b 100644 --- a/.guardlink/graph/by-asset/workspace-config.threats.mmd +++ b/.guardlink/graph/by-asset/workspace-config.threats.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/workspace-config.threats.mmd %% scope: PARTIAL — #workspace-config only — its own threats and controls -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-asset/workspace-link.flows.mmd b/.guardlink/graph/by-asset/workspace-link.flows.mmd index 3e7edbc0..8c9a1a23 100644 --- a/.guardlink/graph/by-asset/workspace-link.flows.mmd +++ b/.guardlink/graph/by-asset/workspace-link.flows.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-asset/workspace-link.flows.mmd %% scope: PARTIAL — #workspace-link and its flow neighbourhood, grown until the drawing stopped fitting — 37 neighbour(s) one hop out are not shown -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/agent-boundary.mmd b/.guardlink/graph/by-boundary/agent-boundary.mmd index d002a967..527a5c13 100644 --- a/.guardlink/graph/by-boundary/agent-boundary.mmd +++ b/.guardlink/graph/by-boundary/agent-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/agent-boundary.mmd %% scope: PARTIAL — the Trust boundary at process spawn between agent-launcher and agentprocess, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/cli-input-boundary.mmd b/.guardlink/graph/by-boundary/cli-input-boundary.mmd index 0efd198c..0d90a14e 100644 --- a/.guardlink/graph/by-boundary/cli-input-boundary.mmd +++ b/.guardlink/graph/by-boundary/cli-input-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/cli-input-boundary.mmd %% scope: PARTIAL — the Trust boundary at CLI argument parsing between cli and userinput, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/codegraph-boundary.mmd b/.guardlink/graph/by-boundary/codegraph-boundary.mmd index 61638946..4adbf4e1 100644 --- a/.guardlink/graph/by-boundary/codegraph-boundary.mmd +++ b/.guardlink/graph/by-boundary/codegraph-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/codegraph-boundary.mmd %% scope: PARTIAL — the Process boundary: an external binary's JSON is parsed defensively and never executed between codegraph and codegraphserver, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/fs-boundary.mmd b/.guardlink/graph/by-boundary/fs-boundary.mmd index 20ee13e4..1384a589 100644 --- a/.guardlink/graph/by-boundary/fs-boundary.mmd +++ b/.guardlink/graph/by-boundary/fs-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/fs-boundary.mmd %% scope: PARTIAL — the Trust boundary between parser and disk I/O between parser and filesystem, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/git-boundary.mmd b/.guardlink/graph/by-boundary/git-boundary.mmd index 729d1ce0..efadc9b6 100644 --- a/.guardlink/graph/by-boundary/git-boundary.mmd +++ b/.guardlink/graph/by-boundary/git-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/git-boundary.mmd %% scope: PARTIAL — the Trust boundary at git command execution between diff and gitrepo, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/llm-api-boundary.mmd b/.guardlink/graph/by-boundary/llm-api-boundary.mmd index cf1e9725..9fc61c42 100644 --- a/.guardlink/graph/by-boundary/llm-api-boundary.mmd +++ b/.guardlink/graph/by-boundary/llm-api-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/llm-api-boundary.mmd %% scope: PARTIAL — the Trust boundary at external API call between llm-client and llmprovider, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/mcp-boundary.mmd b/.guardlink/graph/by-boundary/mcp-boundary.mmd index 234a4413..e7cfc322 100644 --- a/.guardlink/graph/by-boundary/mcp-boundary.mmd +++ b/.guardlink/graph/by-boundary/mcp-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/mcp-boundary.mmd %% scope: PARTIAL — the Trust boundary at MCP protocol between mcp and mcpclient, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/mcp-tool-boundary.mmd b/.guardlink/graph/by-boundary/mcp-tool-boundary.mmd index 589baadf..b601bb49 100644 --- a/.guardlink/graph/by-boundary/mcp-tool-boundary.mmd +++ b/.guardlink/graph/by-boundary/mcp-tool-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/mcp-tool-boundary.mmd %% scope: PARTIAL — the Trust boundary at tool argument parsing between mcp and mcpclient, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/nvd-api-boundary.mmd b/.guardlink/graph/by-boundary/nvd-api-boundary.mmd index 8cd8a96f..35748e19 100644 --- a/.guardlink/graph/by-boundary/nvd-api-boundary.mmd +++ b/.guardlink/graph/by-boundary/nvd-api-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/nvd-api-boundary.mmd %% scope: PARTIAL — the Trust boundary at external API between llm-client and nvd, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-boundary/tui-input-boundary.mmd b/.guardlink/graph/by-boundary/tui-input-boundary.mmd index 461e9164..ded0b4cb 100644 --- a/.guardlink/graph/by-boundary/tui-input-boundary.mmd +++ b/.guardlink/graph/by-boundary/tui-input-boundary.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-boundary/tui-input-boundary.mmd %% scope: PARTIAL — the Trust boundary at interactive input between tui and userinput, and what flows across it -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-feature/dashboard.mmd b/.guardlink/graph/by-feature/dashboard.mmd index 2900d36e..9f2890c4 100644 --- a/.guardlink/graph/by-feature/dashboard.mmd +++ b/.guardlink/graph/by-feature/dashboard.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-feature/dashboard.mmd %% scope: PARTIAL — @feature "Dashboard" only, not the whole model -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/by-feature/mcp-integration.mmd b/.guardlink/graph/by-feature/mcp-integration.mmd index c393c321..351a1ba7 100644 --- a/.guardlink/graph/by-feature/mcp-integration.mmd +++ b/.guardlink/graph/by-feature/mcp-integration.mmd @@ -1,7 +1,7 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: by-feature/mcp-integration.mmd %% scope: PARTIAL — @feature "MCP Integration" only, not the whole model -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/graph/dataflow.mmd b/.guardlink/graph/dataflow.mmd index 0296a3c4..39e2da72 100644 --- a/.guardlink/graph/dataflow.mmd +++ b/.guardlink/graph/dataflow.mmd @@ -1,6 +1,6 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: dataflow.mmd -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If @@ -9,7 +9,7 @@ %% When it was generated and at which commit: ask git. Those move for reasons %% unrelated to the diagram, so they are reported at emission time, not stored. %% --- -%% DRAWS, BUT IS TOO BIG TO READ. dataflow.mmd is 77 nodes / 193 edges, past the 12 / 16 legibility budget (77 nodes against 12, 193 edges against 16). +%% DRAWS, BUT IS TOO BIG TO READ. dataflow.mmd is 77 nodes / 195 edges, past the 12 / 16 legibility budget (77 nodes against 12, 195 edges against 16). %% 12 nodes and 16 edges is what fits a dashboard diagram panel at its %% label size; past it a layered layout grows taller than the panel and %% fitting it shrinks the labels below reading size. Mermaid will draw this @@ -111,8 +111,8 @@ graph LR exportfile["🧩 ExportFile"] annotations["🧩 Annotations"] annotationsource["🧩 AnnotationSource"] - featurename["🧩 FeatureName"] report["🧩 GuardLink.Report · pii"] + featurename["🧩 FeatureName"] markdown["🧩 Markdown"] agentproposal["🧩 AgentProposal"] proposalledger["🧩 ProposalLedger"] @@ -213,6 +213,7 @@ graph LR threatmodel -- "📡 generateDashboardHTML" --> dashboard gitconfig -- "🗄️ readFileSync" --> dashboard dashboard -- "📡 RepoLinks" --> dashboardhtml + threatmodel -- "📡 summarizeReach" --> dashboard threatmodel -- "📡 buildClaims" --> dashboard diagramsource -- "📡 checkRenderBudget" --> dashboard gitrepo -- "📡 parseAtRef" --> dashboard @@ -284,6 +285,7 @@ graph LR ledgerfile -- "📡 classifyClaims" --> parser cli -- "📡 applyVerification" --> ledgerfile threatmodel -- "📡 findUnmitigatedPaths" --> parser + threatmodel -- "📡 summarizeReach" --> report featurename -- "📡 filtered_by_features" --> report threatmodel -- "📡 generateReport" --> report report -- "📡 return" --> markdown diff --git a/.guardlink/graph/index.md b/.guardlink/graph/index.md index 7bf50a54..9d020082 100644 --- a/.guardlink/graph/index.md +++ b/.guardlink/graph/index.md @@ -82,7 +82,7 @@ size so you know which you are about to open. | File | What it shows | Size | |---|---|---| | [`threat-graph.mmd`](threat-graph.mmd) | Every component, the threats declared on it, and the controls that answer them. | 180 edges — **past the readable size** | -| [`dataflow.mmd`](dataflow.mmd) | Every `@flows` between components, with trust boundaries drawn as zones. | 193 edges — **past the readable size** | +| [`dataflow.mmd`](dataflow.mmd) | Every `@flows` between components, with trust boundaries drawn as zones. | 195 edges — **past the readable size** | | [`attack-surface.mmd`](attack-surface.mmd) | Exposures per component, worst first. | 0 edges | ## One feature at a time @@ -106,6 +106,6 @@ size so you know which you are about to open. --- -Generated by guardlink@2.1.0 from annotation hash `sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293`. If that +Generated by guardlink@2.1.0 from annotation hash `sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b`. If that differs from what `guardlink status .` reports, everything here is stale — regenerate rather than trusting it. diff --git a/.guardlink/graph/threat-graph.mmd b/.guardlink/graph/threat-graph.mmd index d2a93e32..f1873502 100644 --- a/.guardlink/graph/threat-graph.mmd +++ b/.guardlink/graph/threat-graph.mmd @@ -1,6 +1,6 @@ %% GENERATED FILE — do not edit. Regenerate with: guardlink artifacts . %% artifact: threat-graph.mmd -%% annotation_hash: sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293 +%% annotation_hash: sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b %% generator: guardlink@2.1.0 %% --- %% This diagram is derived from the annotations in this repository. If diff --git a/.guardlink/model.json b/.guardlink/model.json index 9a1ba85d..f233d623 100644 --- a/.guardlink/model.json +++ b/.guardlink/model.json @@ -1,12 +1,12 @@ { "provenance": { - "annotation_hash": "sha256-v3:9babda79ed52b602afa4ff8920c7a1e2743162457b8a33a234491d30019b2293", + "annotation_hash": "sha256-v3:7699fd36a4f42f9233f7bb6b81030a15c52f45618f34baa20928da749b08203b", "generator": "guardlink@2.1.0" }, "version": "1.2.0", "project": "guardlink", - "source_files": 165, - "annotations_parsed": 885, + "source_files": 169, + "annotations_parsed": 891, "annotated_files": [ ".guardlink/definitions.ts", "src/agents/config.ts", @@ -47,6 +47,7 @@ "src/dashboard/html.ts", "src/dashboard/index.ts", "src/dashboard/links.ts", + "src/dashboard/pages/agents.ts", "src/dashboard/pages/analytics.ts", "src/dashboard/pages/assets.ts", "src/dashboard/pages/attribution.ts", @@ -126,6 +127,9 @@ "src/playbooks/select.ts", "src/playbooks/skills.ts", "src/playbooks/types.ts", + "src/reach/index.ts", + "src/reach/summary.ts", + "src/report/agent-reach.ts", "src/report/index.ts", "src/report/mermaid.ts", "src/report/report.ts", @@ -948,7 +952,7 @@ "description": "join() constrains reads to .guardlink/", "location": { "file": "src/analyze/index.ts", - "line": 799 + "line": 839 } }, { @@ -1208,7 +1212,7 @@ "description": "Diagram labels are sanitized before emission as Mermaid source", "location": { "file": "src/dashboard/diagrams.ts", - "line": 15 + "line": 16 } }, { @@ -1228,7 +1232,7 @@ "description": "esc() HTML-encodes every interpolated value in every page module; serialized data escapes closing script tags before embedding in "\n */\nexport function q(): void {}\n', + })); + const out = generateDashboardHTML(m); + for (const id of ['agents', 'data']) { + expect(page(out, id)).not.toContain('alert'); + } + expect(page(out, 'agents')).toContain('<img src=x onerror=alert(1)>'); + }); +}); + +// ─── The CLI ───────────────────────────────────────────────────────── + +describe('guardlink report --agents', () => { + const cli = join(repoRoot, 'src', 'cli', 'index.ts'); + const tsx = createRequire(import.meta.url).resolve('tsx/cli'); + const run = (cwd: string, ...args: string[]) => new Promise<{ status: number; stderr: string }>(resolve => { + execFile(process.execPath, [tsx, cli, ...args], { cwd, encoding: 'utf-8' }, (err, _stdout, stderr) => { + const code = (err as { code?: number | string } | null)?.code; + resolve({ status: typeof code === 'number' ? code : err ? 1 : 0, stderr }); + }); + }); + + it('writes the agent threat model alone, and the full report still carries the section', async () => { + const root = mkdtempSync(join(tmpdir(), 'gl-reach-cli-')); + roots.push(root); + cpSync(FIXTURE, root, { recursive: true, filter: src => !src.includes(`${'/'}golden`) }); + + const agents = await run(root, 'report', '.', '--agents'); + expect(agents.status, agents.stderr).toBe(0); + const md = readFileSync(join(root, 'threat-model-agents.md'), 'utf-8'); + expect(md.startsWith('# Agent and LLM Threat Model — support-desk')).toBe(true); + expect(md).toContain('### Unentitled Reaches'); + expect(existsSync(join(root, 'threat-model.json'))).toBe(false); + + const full = await run(root, 'report', '.'); + expect(full.status, full.stderr).toBe(0); + expect(readFileSync(join(root, 'threat-model.md'), 'utf-8')).toContain('## Agents and LLM Reach'); + }, 60_000); +}); diff --git a/tests/fixtures/support-desk/FIXTURE.md b/tests/fixtures/support-desk/FIXTURE.md index 2cc397a4..c24b587b 100644 --- a/tests/fixtures/support-desk/FIXTURE.md +++ b/tests/fixtures/support-desk/FIXTURE.md @@ -31,3 +31,11 @@ The `@entitles` lines have no accepted proposal behind them, so It does not perturb this repository's own model: `**/tests/**` is in the parser's `DEFAULT_EXCLUDE`. + +`golden/` holds what `tests/agent-reach-surfaces.test.ts` pins from this +fixture for the human-facing surfaces: the derived view the dashboard's Agents +& Reach page and the report both draw (`reach-summary.json`), the report's +"Agents and LLM Reach" section (`agent-reach-section.md`), the agent-only +report (`threat-model-agents.md`) and the reach diagram (`agent-reach.mmd`). +Editing the fixture changes them too; regenerate with +`npx vitest run tests/agent-reach-surfaces.test.ts -u` and read the diff. diff --git a/tests/fixtures/support-desk/golden/agent-reach-section.md b/tests/fixtures/support-desk/golden/agent-reach-section.md new file mode 100644 index 00000000..1d1a8336 --- /dev/null +++ b/tests/fixtures/support-desk/golden/agent-reach-section.md @@ -0,0 +1,126 @@ +What the code lets each agent and principal do — `@agents` and `@reaches` (can invoke), `@effects` (what the +code does) and `@gates` (who decides first) — set against what a human approved with `@entitles`. An effect is +tied to an actor only when both are written in one doc-block, bound to the same code; reaching an effect +through calls across handlers takes a call graph and is not inferred here. + +| Measure | Count | +|---------|-------| +| Agents (`@agents`) | 1 | +| Other principals (`@reaches`) | 1 | +| Reaches | 7 | +| **Unentitled reaches** | **5** | +| Effects | 9 (7 mutating) | +| **Ungated mutations** | **5** | +| Gates | 2 | +| Egress from a reach | 0 | +| Injection-to-tool routes | 0 | + +### #support-agent — AI agent + +LLM agent; acts for the signed-in customer + +6 capabilities, 4 unentitled, 3 ungated mutations. + +| Capability | On | As | Entitled | What it leads to | Location | +|------------|----|----|----------|------------------|----------| +| `lookup-order` | #tool-surface | #agent-session | yes | read #orders-db | src/tools.ts:5 | +| `run-sql` | #tool-surface | — | **no** | **delete (ungated)** #orders-db, **write (ungated)** #users-db | src/tools.ts:14 | +| `issue-refund` | #tool-surface | — | yes | spend (gated by #support-human) #payments | src/tools.ts:25 | +| `search-kb` | #tool-surface | — | **no** | read #kb | src/tools.ts:34 | +| `fetch-url` | #tool-surface | — | **no** | — | src/tools.ts:43 | +| `mcp-files` | #tool-surface | — | **no** | **write (ungated)** #host-fs | src/tools.ts:51 | + +### #ci-runner — principal + +Release pipeline + +1 capability, 1 unentitled, 1 ungated mutation. + +| Capability | On | As | Entitled | What it leads to | Location | +|------------|----|----|----------|------------------|----------| +| `publish-package` | #registry | — | **no** | **write (ungated)** #registry | src/billing.ts:12 | + +### Reach Map + +Rows are actors, columns the assets they reach. A capability is marked ✗ when no cited `@entitles` covers it; +an effect is marked ungated when it mutates and no `@gates` stands in front of it. + +| Actor | #tool-surface | #orders-db | #users-db | #payments | #kb | #host-fs | #registry | #outbox | +|-------|---|---|---|---|---|---|---|---| +| #support-agent (agent) | `lookup-order` ✓
`run-sql` ✗
`issue-refund` ✓
`search-kb` ✗
`fetch-url` ✗
`mcp-files` ✗ | read
**delete (ungated)** | **write (ungated)** | spend (gated by #support-human) | read | **write (ungated)** | · | · | +| #ci-runner | · | · | · | · | · | · | `publish-package` ✗
**write (ungated)** | · | +| _not tied to a reach_ | · | · | · | **spend (ungated)** | · | · | · | notify (gated by #support-human) | + +### Unentitled Reaches + +Capabilities the code hands out that no cited `@entitles` covers: can minus may. For an agent this is the +Excessive Agency list. Only a human closes one, by accepting an entitlement proposal (`guardlink entitle --propose`). + +| Actor | Capability | On | Why nothing covers it | Location | +|-------|------------|----|-----------------------|----------| +| #ci-runner | `publish-package` | #registry | no `@entitles` for this actor and capability | src/billing.ts:12 | +| #support-agent (agent) | `run-sql` | #tool-surface | no `@entitles` for this actor and capability | src/tools.ts:14 | +| #support-agent (agent) | `search-kb` | #tool-surface | the entitlement is for another asset (src/tools.ts:36) | src/tools.ts:34 | +| #support-agent (agent) | `fetch-url` | #tool-surface | the entitlement cites no authorization code, so it covers nothing (src/tools.ts:44) | src/tools.ts:43 | +| #support-agent (agent) | `mcp-files` | #tool-surface | no `@entitles` for this actor and capability | src/tools.ts:51 | + +### Ungated Mutations + +Effects other than `read` with no `@gates` in front of them. A gate suppresses nothing; its absence means +nothing in the model says a person or a check decides before the effect lands. + +| Effect | Asset | As | Reached through | Location | +|--------|-------|----|-----------------|----------| +| spend | #payments | #billing-sa | _no reach on this code_; #support-human for `issue-refund` does not cover it: the gate is for one capability, and no reach on this code says which capability gets here | src/billing.ts:5 | +| write | #registry | — | #ci-runner `publish-package` | src/billing.ts:13 | +| delete | #orders-db | — | #support-agent `run-sql` | src/tools.ts:15 | +| write | #users-db | — | #support-agent `run-sql` | src/tools.ts:16 | +| write | #host-fs | — | #support-agent `mcp-files` | src/tools.ts:52 | + +### Gates + +| Asset | Approver | For | Stands in front of | Location | +|-------|----------|-----|--------------------|----------| +| #payments | #support-human | `issue-refund` | spend on #payments (src/tools.ts:26) | src/approval.ts:5 | +| #outbox | #support-human | every capability | notify on #outbox (src/approval.ts:13) | src/approval.ts:12 | + +### Effects Not Tied to a Reach + +No `@agents` or `@reaches` is bound to the same code, so which principal reaches these +is a call-graph question. They still count as ungated mutations when nothing gates them. + +- notify (gated by #support-human) on #outbox (src/approval.ts:13) +- **spend (ungated)** on #payments (src/billing.ts:5) + +### OWASP Top 10 for LLM Applications + +Each row is a target for review or test, not a finding the model has proved. + +| Item | What GuardLink looks for | Found | +|------|--------------------------|-------| +| LLM06 Excessive Agency | Unentitled @agents (functionality), an effect running as a broader identity than the agent presents (permissions), and mutations with no @gates (autonomy). | 7 | +| LLM01 Prompt Injection | Input from outside the model that @flows into an agent which can reach an ungated mutation. | 0 | +| LLM05 Improper Output Handling | A write, delete, execute or notify bound to the same code as the agent's tool, so model output reaches it directly. | 3 | + +**LLM06 Excessive Agency** + +- _functionality_ — #support-agent: can run-sql on #tool-surface and no cited @entitles covers it (src/tools.ts:14) +- _functionality_ — #support-agent: can search-kb on #tool-surface and no cited @entitles covers it (src/tools.ts:34) +- _functionality_ — #support-agent: can fetch-url on #tool-surface and no cited @entitles covers it (src/tools.ts:43) +- _functionality_ — #support-agent: can mcp-files on #tool-surface and no cited @entitles covers it (src/tools.ts:51) +- _autonomy_ — #support-agent: delete on #orders-db through run-sql, with no @gates in front of it (src/tools.ts:15) +- _autonomy_ — #support-agent: write on #users-db through run-sql, with no @gates in front of it (src/tools.ts:16) +- _autonomy_ — #support-agent: write on #host-fs through mcp-files, with no @gates in front of it (src/tools.ts:52) + +**LLM05 Improper Output Handling** + +- _model output into an effect_ — #support-agent: run-sql hands model-written arguments to a delete on #orders-db in the same code (src/tools.ts:15) +- _model output into an effect_ — #support-agent: run-sql hands model-written arguments to a write on #users-db in the same code (src/tools.ts:16) +- _model output into an effect_ — #support-agent: mcp-files hands model-written arguments to a write on #host-fs in the same code (src/tools.ts:52) + +### Open Exposures on Reached Assets + +| Severity | Asset | Threat | Description | Location | +|----------|-------|--------|-------------|----------| +| high | #users-db | #excessive-agency | Reachable from the agent's tool surface, nothing approves the write | src/tools.ts:17 | + diff --git a/tests/fixtures/support-desk/golden/agent-reach.mmd b/tests/fixtures/support-desk/golden/agent-reach.mmd new file mode 100644 index 00000000..1412fe0b --- /dev/null +++ b/tests/fixtures/support-desk/golden/agent-reach.mmd @@ -0,0 +1,34 @@ +%%{init: {"flowchart": {"nodeSpacing": 40, "rankSpacing": 90, "curve": "basis", "htmlLabels": false}}}%% +graph LR + A_support_agent(["#support-agent · AI agent"]):::agent + A_ci_runner["#ci-runner"]:::principal + A_support_human(("#support-human")):::approver + S_registry[("#registry")] + A_ci_runner -. "unentitled: publish-package" .-> S_registry + A_ci_runner == "write · no gate" ==> S_registry + S_tool_surface[("#tool-surface")] + A_support_agent -. "unentitled: run-sql, search-kb, fetch-url, mcp-files · entitled: lookup-order, issue-refund" .-> S_tool_surface + S_orders_db[("#orders-db")] + A_support_agent == "delete · no gate" ==> S_orders_db + A_support_agent -- "read" --> S_orders_db + S_users_db[("#users-db")] + A_support_agent == "write · no gate" ==> S_users_db + S_payments[("#payments")] + A_support_agent -- "spend gated" --> S_payments + S_kb[("#kb")] + A_support_agent -- "read" --> S_kb + S_host_fs[("#host-fs")] + A_support_agent == "write · no gate" ==> S_host_fs + X_loose["code not tied to a reach"]:::loose + S_outbox[("#outbox")] + X_loose -- "notify" --> S_outbox + X_loose == "spend" ==> S_payments + A_support_human -. "gates issue-refund" .-> S_payments + A_support_human -. "gates" .-> S_outbox + classDef agent stroke:#33d49d,stroke-width:2px + classDef principal stroke:#1a98d0,stroke-width:1.5px + classDef approver stroke:#33d49d,stroke-dasharray:4 3 + classDef loose stroke-dasharray:4 3 + classDef external stroke:#ea1d1d,stroke-dasharray:4 3 + linkStyle 0,1,2,3,5,8,10 stroke:#ea1d1d,stroke-width:2px + linkStyle 11,12 stroke:#33d49d diff --git a/tests/fixtures/support-desk/golden/reach-summary.json b/tests/fixtures/support-desk/golden/reach-summary.json new file mode 100644 index 00000000..5461b6e6 --- /dev/null +++ b/tests/fixtures/support-desk/golden/reach-summary.json @@ -0,0 +1,677 @@ +{ + "actors": [ + { + "key": "support-agent", + "ref": "#support-agent", + "name": "Support_Agent", + "description": "LLM agent; acts for the signed-in customer", + "agent": true, + "declared": true, + "reaches": 6, + "unentitled": 4, + "ungated": 3, + "approves": 0, + "loc": { + "file": ".guardlink/definitions.ts", + "line": 16 + } + }, + { + "key": "ci-runner", + "ref": "#ci-runner", + "name": "CI_Runner", + "description": "Release pipeline", + "agent": false, + "declared": true, + "reaches": 1, + "unentitled": 1, + "ungated": 1, + "approves": 0, + "loc": { + "file": ".guardlink/definitions.ts", + "line": 18 + } + }, + { + "key": "support-human", + "ref": "#support-human", + "name": "Support_Human", + "description": "Approves refunds and outbound email in the review queue", + "agent": false, + "declared": true, + "reaches": 0, + "unentitled": 0, + "ungated": 0, + "approves": 2, + "loc": { + "file": ".guardlink/definitions.ts", + "line": 17 + } + } + ], + "columns": [ + { + "key": "tool-surface", + "ref": "#tool-surface", + "declared": true + }, + { + "key": "orders-db", + "ref": "#orders-db", + "declared": true + }, + { + "key": "users-db", + "ref": "#users-db", + "declared": true + }, + { + "key": "payments", + "ref": "#payments", + "declared": true + }, + { + "key": "kb", + "ref": "#kb", + "declared": true + }, + { + "key": "host-fs", + "ref": "#host-fs", + "declared": true + }, + { + "key": "registry", + "ref": "#registry", + "declared": true + }, + { + "key": "outbox", + "ref": "#outbox", + "declared": true + } + ], + "cells": [ + { + "actor": "ci-runner", + "asset": "registry", + "capabilities": [ + { + "capability": "publish-package", + "entitled": false, + "loc": { + "file": "src/billing.ts", + "line": 12 + } + } + ], + "effects": [ + { + "effect": "write", + "mutating": true, + "gated": false, + "approvers": [], + "via": [ + "publish-package" + ], + "loc": { + "file": "src/billing.ts", + "line": 13 + } + } + ] + }, + { + "actor": "support-agent", + "asset": "tool-surface", + "capabilities": [ + { + "capability": "lookup-order", + "entitled": true, + "identity": "#agent-session", + "loc": { + "file": "src/tools.ts", + "line": 5 + } + }, + { + "capability": "run-sql", + "entitled": false, + "loc": { + "file": "src/tools.ts", + "line": 14 + } + }, + { + "capability": "issue-refund", + "entitled": true, + "loc": { + "file": "src/tools.ts", + "line": 25 + } + }, + { + "capability": "search-kb", + "entitled": false, + "loc": { + "file": "src/tools.ts", + "line": 34 + } + }, + { + "capability": "fetch-url", + "entitled": false, + "loc": { + "file": "src/tools.ts", + "line": 43 + } + }, + { + "capability": "mcp-files", + "entitled": false, + "loc": { + "file": "src/tools.ts", + "line": 51 + } + } + ], + "effects": [] + }, + { + "actor": "support-agent", + "asset": "orders-db", + "capabilities": [], + "effects": [ + { + "effect": "read", + "mutating": false, + "gated": null, + "approvers": [], + "via": [ + "lookup-order" + ], + "identity": "#agent-session", + "loc": { + "file": "src/tools.ts", + "line": 6 + } + }, + { + "effect": "delete", + "mutating": true, + "gated": false, + "approvers": [], + "via": [ + "run-sql" + ], + "loc": { + "file": "src/tools.ts", + "line": 15 + } + } + ] + }, + { + "actor": "support-agent", + "asset": "users-db", + "capabilities": [], + "effects": [ + { + "effect": "write", + "mutating": true, + "gated": false, + "approvers": [], + "via": [ + "run-sql" + ], + "loc": { + "file": "src/tools.ts", + "line": 16 + } + } + ] + }, + { + "actor": "support-agent", + "asset": "payments", + "capabilities": [], + "effects": [ + { + "effect": "spend", + "mutating": true, + "gated": true, + "approvers": [ + "#support-human" + ], + "via": [ + "issue-refund" + ], + "identity": "#billing-sa", + "loc": { + "file": "src/tools.ts", + "line": 26 + } + } + ] + }, + { + "actor": "support-agent", + "asset": "kb", + "capabilities": [], + "effects": [ + { + "effect": "read", + "mutating": false, + "gated": null, + "approvers": [], + "via": [ + "search-kb" + ], + "loc": { + "file": "src/tools.ts", + "line": 35 + } + } + ] + }, + { + "actor": "support-agent", + "asset": "host-fs", + "capabilities": [], + "effects": [ + { + "effect": "write", + "mutating": true, + "gated": false, + "approvers": [], + "via": [ + "mcp-files" + ], + "loc": { + "file": "src/tools.ts", + "line": 52 + } + } + ] + } + ], + "loose": [ + { + "asset": "outbox", + "effects": [ + { + "effect": "notify", + "mutating": true, + "gated": true, + "approvers": [ + "#support-human" + ], + "via": [], + "loc": { + "file": "src/approval.ts", + "line": 13 + } + } + ] + }, + { + "asset": "payments", + "effects": [ + { + "effect": "spend", + "mutating": true, + "gated": false, + "approvers": [], + "via": [], + "identity": "#billing-sa", + "loc": { + "file": "src/billing.ts", + "line": 5 + } + } + ] + } + ], + "unentitled": [ + { + "actor": "#ci-runner", + "agent": false, + "capability": "publish-package", + "asset": "#registry", + "description": "npm publish in the release workflow", + "loc": { + "file": "src/billing.ts", + "line": 12 + }, + "near_misses": [] + }, + { + "actor": "#support-agent", + "agent": true, + "capability": "run-sql", + "asset": "#tool-surface", + "description": "Debug tool, still registered", + "loc": { + "file": "src/tools.ts", + "line": 14 + }, + "near_misses": [] + }, + { + "actor": "#support-agent", + "agent": true, + "capability": "search-kb", + "asset": "#tool-surface", + "loc": { + "file": "src/tools.ts", + "line": 34 + }, + "near_misses": [ + { + "blocker": "other-asset", + "reason": "the entitlement is for another asset", + "asset": "#kb", + "citation": "src/agent/policy.ts:18", + "loc": { + "file": "src/tools.ts", + "line": 36 + } + } + ] + }, + { + "actor": "#support-agent", + "agent": true, + "capability": "fetch-url", + "asset": "#tool-surface", + "description": "Fetches any URL the model names", + "loc": { + "file": "src/tools.ts", + "line": 43 + }, + "near_misses": [ + { + "blocker": "uncited", + "reason": "the entitlement cites no authorization code, so it covers nothing", + "loc": { + "file": "src/tools.ts", + "line": 44 + } + } + ] + }, + { + "actor": "#support-agent", + "agent": true, + "capability": "mcp-files", + "asset": "#tool-surface", + "description": "Filesystem MCP server rooted at /", + "loc": { + "file": "src/tools.ts", + "line": 51 + }, + "near_misses": [] + } + ], + "ungated": [ + { + "effect": "spend", + "asset": "#payments", + "identity": "#billing-sa", + "description": "Nightly sweep retries failed refunds", + "loc": { + "file": "src/billing.ts", + "line": 5 + }, + "via": [], + "gate_near_misses": [ + { + "approver": "#support-human", + "capability": "issue-refund", + "blocker": "capability-unknown", + "reason": "the gate is for one capability, and no reach on this code says which capability gets here" + } + ], + "agent": false + }, + { + "effect": "write", + "asset": "#registry", + "description": "publish", + "loc": { + "file": "src/billing.ts", + "line": 13 + }, + "via": [ + { + "actor": "#ci-runner", + "agent": false, + "capability": "publish-package" + } + ], + "gate_near_misses": [], + "agent": false + }, + { + "effect": "delete", + "asset": "#orders-db", + "description": "runRaw executes the model's SQL", + "loc": { + "file": "src/tools.ts", + "line": 15 + }, + "via": [ + { + "actor": "#support-agent", + "agent": true, + "capability": "run-sql" + } + ], + "gate_near_misses": [], + "agent": true + }, + { + "effect": "write", + "asset": "#users-db", + "description": "runRaw executes the model's SQL", + "loc": { + "file": "src/tools.ts", + "line": 16 + }, + "via": [ + { + "actor": "#support-agent", + "agent": true, + "capability": "run-sql" + } + ], + "gate_near_misses": [], + "agent": true + }, + { + "effect": "write", + "asset": "#host-fs", + "description": "mountFiles", + "loc": { + "file": "src/tools.ts", + "line": 52 + }, + "via": [ + { + "actor": "#support-agent", + "agent": true, + "capability": "mcp-files" + } + ], + "gate_near_misses": [], + "agent": true + } + ], + "gates": [ + { + "asset": "#payments", + "approver": "#support-human", + "capability": "issue-refund", + "description": "requireApproval() parks the refund until a human approves it", + "loc": { + "file": "src/approval.ts", + "line": 5 + }, + "covers": [ + { + "effect": "spend", + "asset": "#payments", + "loc": { + "file": "src/tools.ts", + "line": 26 + } + } + ] + }, + { + "asset": "#outbox", + "approver": "#support-human", + "description": "Every outbound email waits in the review queue", + "loc": { + "file": "src/approval.ts", + "line": 12 + }, + "covers": [ + { + "effect": "notify", + "asset": "#outbox", + "loc": { + "file": "src/approval.ts", + "line": 13 + } + } + ] + } + ], + "egress": [], + "injection": [], + "owasp": [ + { + "id": "LLM06", + "title": "Excessive Agency", + "basis": "Unentitled @agents (functionality), an effect running as a broader identity than the agent presents (permissions), and mutations with no @gates (autonomy).", + "items": [ + { + "facet": "functionality", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 14 + }, + "text": "can run-sql on #tool-surface and no cited @entitles covers it" + }, + { + "facet": "functionality", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 34 + }, + "text": "can search-kb on #tool-surface and no cited @entitles covers it" + }, + { + "facet": "functionality", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 43 + }, + "text": "can fetch-url on #tool-surface and no cited @entitles covers it" + }, + { + "facet": "functionality", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 51 + }, + "text": "can mcp-files on #tool-surface and no cited @entitles covers it" + }, + { + "facet": "autonomy", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 15 + }, + "text": "delete on #orders-db through run-sql, with no @gates in front of it" + }, + { + "facet": "autonomy", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 16 + }, + "text": "write on #users-db through run-sql, with no @gates in front of it" + }, + { + "facet": "autonomy", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 52 + }, + "text": "write on #host-fs through mcp-files, with no @gates in front of it" + } + ] + }, + { + "id": "LLM01", + "title": "Prompt Injection", + "basis": "Input from outside the model that @flows into an agent which can reach an ungated mutation.", + "items": [] + }, + { + "id": "LLM05", + "title": "Improper Output Handling", + "basis": "A write, delete, execute or notify bound to the same code as the agent's tool, so model output reaches it directly.", + "items": [ + { + "facet": "model output into an effect", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 15 + }, + "text": "run-sql hands model-written arguments to a delete on #orders-db in the same code" + }, + { + "facet": "model output into an effect", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 16 + }, + "text": "run-sql hands model-written arguments to a write on #users-db in the same code" + }, + { + "facet": "model output into an effect", + "agent": "#support-agent", + "loc": { + "file": "src/tools.ts", + "line": 52 + }, + "text": "mcp-files hands model-written arguments to a write on #host-fs in the same code" + } + ] + } + ], + "totals": { + "agents": 1, + "principals": 1, + "reaches": 7, + "unentitled": 5, + "effects": 9, + "mutations": 7, + "ungated": 5, + "gates": 2, + "egress": 0, + "injection": 0 + } +} diff --git a/tests/fixtures/support-desk/golden/threat-model-agents.md b/tests/fixtures/support-desk/golden/threat-model-agents.md new file mode 100644 index 00000000..f15935e9 --- /dev/null +++ b/tests/fixtures/support-desk/golden/threat-model-agents.md @@ -0,0 +1,137 @@ +# Agent and LLM Threat Model — support-desk + +> Generated: +> Files scanned: 4 | Annotations: 38 + +This is the agent part of the threat model: what each embedded LLM agent and other principal can reach, +what of that a human approved, and what acts with no one deciding first. `guardlink report` without +`--agents` places the same section in the full threat model. + +## Agents and LLM Reach + +What the code lets each agent and principal do — `@agents` and `@reaches` (can invoke), `@effects` (what the +code does) and `@gates` (who decides first) — set against what a human approved with `@entitles`. An effect is +tied to an actor only when both are written in one doc-block, bound to the same code; reaching an effect +through calls across handlers takes a call graph and is not inferred here. + +| Measure | Count | +|---------|-------| +| Agents (`@agents`) | 1 | +| Other principals (`@reaches`) | 1 | +| Reaches | 7 | +| **Unentitled reaches** | **5** | +| Effects | 9 (7 mutating) | +| **Ungated mutations** | **5** | +| Gates | 2 | +| Egress from a reach | 0 | +| Injection-to-tool routes | 0 | + +### #support-agent — AI agent + +LLM agent; acts for the signed-in customer + +6 capabilities, 4 unentitled, 3 ungated mutations. + +| Capability | On | As | Entitled | What it leads to | Location | +|------------|----|----|----------|------------------|----------| +| `lookup-order` | #tool-surface | #agent-session | yes | read #orders-db | src/tools.ts:5 | +| `run-sql` | #tool-surface | — | **no** | **delete (ungated)** #orders-db, **write (ungated)** #users-db | src/tools.ts:14 | +| `issue-refund` | #tool-surface | — | yes | spend (gated by #support-human) #payments | src/tools.ts:25 | +| `search-kb` | #tool-surface | — | **no** | read #kb | src/tools.ts:34 | +| `fetch-url` | #tool-surface | — | **no** | — | src/tools.ts:43 | +| `mcp-files` | #tool-surface | — | **no** | **write (ungated)** #host-fs | src/tools.ts:51 | + +### #ci-runner — principal + +Release pipeline + +1 capability, 1 unentitled, 1 ungated mutation. + +| Capability | On | As | Entitled | What it leads to | Location | +|------------|----|----|----------|------------------|----------| +| `publish-package` | #registry | — | **no** | **write (ungated)** #registry | src/billing.ts:12 | + +### Reach Map + +Rows are actors, columns the assets they reach. A capability is marked ✗ when no cited `@entitles` covers it; +an effect is marked ungated when it mutates and no `@gates` stands in front of it. + +| Actor | #tool-surface | #orders-db | #users-db | #payments | #kb | #host-fs | #registry | #outbox | +|-------|---|---|---|---|---|---|---|---| +| #support-agent (agent) | `lookup-order` ✓
`run-sql` ✗
`issue-refund` ✓
`search-kb` ✗
`fetch-url` ✗
`mcp-files` ✗ | read
**delete (ungated)** | **write (ungated)** | spend (gated by #support-human) | read | **write (ungated)** | · | · | +| #ci-runner | · | · | · | · | · | · | `publish-package` ✗
**write (ungated)** | · | +| _not tied to a reach_ | · | · | · | **spend (ungated)** | · | · | · | notify (gated by #support-human) | + +### Unentitled Reaches + +Capabilities the code hands out that no cited `@entitles` covers: can minus may. For an agent this is the +Excessive Agency list. Only a human closes one, by accepting an entitlement proposal (`guardlink entitle --propose`). + +| Actor | Capability | On | Why nothing covers it | Location | +|-------|------------|----|-----------------------|----------| +| #ci-runner | `publish-package` | #registry | no `@entitles` for this actor and capability | src/billing.ts:12 | +| #support-agent (agent) | `run-sql` | #tool-surface | no `@entitles` for this actor and capability | src/tools.ts:14 | +| #support-agent (agent) | `search-kb` | #tool-surface | the entitlement is for another asset (src/tools.ts:36) | src/tools.ts:34 | +| #support-agent (agent) | `fetch-url` | #tool-surface | the entitlement cites no authorization code, so it covers nothing (src/tools.ts:44) | src/tools.ts:43 | +| #support-agent (agent) | `mcp-files` | #tool-surface | no `@entitles` for this actor and capability | src/tools.ts:51 | + +### Ungated Mutations + +Effects other than `read` with no `@gates` in front of them. A gate suppresses nothing; its absence means +nothing in the model says a person or a check decides before the effect lands. + +| Effect | Asset | As | Reached through | Location | +|--------|-------|----|-----------------|----------| +| spend | #payments | #billing-sa | _no reach on this code_; #support-human for `issue-refund` does not cover it: the gate is for one capability, and no reach on this code says which capability gets here | src/billing.ts:5 | +| write | #registry | — | #ci-runner `publish-package` | src/billing.ts:13 | +| delete | #orders-db | — | #support-agent `run-sql` | src/tools.ts:15 | +| write | #users-db | — | #support-agent `run-sql` | src/tools.ts:16 | +| write | #host-fs | — | #support-agent `mcp-files` | src/tools.ts:52 | + +### Gates + +| Asset | Approver | For | Stands in front of | Location | +|-------|----------|-----|--------------------|----------| +| #payments | #support-human | `issue-refund` | spend on #payments (src/tools.ts:26) | src/approval.ts:5 | +| #outbox | #support-human | every capability | notify on #outbox (src/approval.ts:13) | src/approval.ts:12 | + +### Effects Not Tied to a Reach + +No `@agents` or `@reaches` is bound to the same code, so which principal reaches these +is a call-graph question. They still count as ungated mutations when nothing gates them. + +- notify (gated by #support-human) on #outbox (src/approval.ts:13) +- **spend (ungated)** on #payments (src/billing.ts:5) + +### OWASP Top 10 for LLM Applications + +Each row is a target for review or test, not a finding the model has proved. + +| Item | What GuardLink looks for | Found | +|------|--------------------------|-------| +| LLM06 Excessive Agency | Unentitled @agents (functionality), an effect running as a broader identity than the agent presents (permissions), and mutations with no @gates (autonomy). | 7 | +| LLM01 Prompt Injection | Input from outside the model that @flows into an agent which can reach an ungated mutation. | 0 | +| LLM05 Improper Output Handling | A write, delete, execute or notify bound to the same code as the agent's tool, so model output reaches it directly. | 3 | + +**LLM06 Excessive Agency** + +- _functionality_ — #support-agent: can run-sql on #tool-surface and no cited @entitles covers it (src/tools.ts:14) +- _functionality_ — #support-agent: can search-kb on #tool-surface and no cited @entitles covers it (src/tools.ts:34) +- _functionality_ — #support-agent: can fetch-url on #tool-surface and no cited @entitles covers it (src/tools.ts:43) +- _functionality_ — #support-agent: can mcp-files on #tool-surface and no cited @entitles covers it (src/tools.ts:51) +- _autonomy_ — #support-agent: delete on #orders-db through run-sql, with no @gates in front of it (src/tools.ts:15) +- _autonomy_ — #support-agent: write on #users-db through run-sql, with no @gates in front of it (src/tools.ts:16) +- _autonomy_ — #support-agent: write on #host-fs through mcp-files, with no @gates in front of it (src/tools.ts:52) + +**LLM05 Improper Output Handling** + +- _model output into an effect_ — #support-agent: run-sql hands model-written arguments to a delete on #orders-db in the same code (src/tools.ts:15) +- _model output into an effect_ — #support-agent: run-sql hands model-written arguments to a write on #users-db in the same code (src/tools.ts:16) +- _model output into an effect_ — #support-agent: mcp-files hands model-written arguments to a write on #host-fs in the same code (src/tools.ts:52) + +### Open Exposures on Reached Assets + +| Severity | Asset | Threat | Description | Location | +|----------|-------|--------|-------------|----------| +| high | #users-db | #excessive-agency | Reachable from the agent's tool surface, nothing approves the write | src/tools.ts:17 | +