arkaos 4.47.0 → 4.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THE-ARKAOS-GUIDE.md +1 -1
- package/VERSION +1 -1
- package/core/egress/policy.py +84 -32
- package/core/kb/__init__.py +9 -0
- package/core/kb/nlm_client.py +883 -0
- package/harness/codex/AGENTS.md +1 -1
- package/harness/copilot/copilot-instructions.md +1 -1
- package/harness/cursor/rules/arkaos.mdc +2 -2
- package/harness/gemini/GEMINI.md +1 -1
- package/harness/opencode/AGENTS.md +1 -1
- package/harness/opencode/agents/arka-architect-gabriel.md +1 -1
- package/harness/opencode/agents/arka-brand-director-valentina.md +1 -1
- package/harness/opencode/agents/arka-cfo-helena.md +1 -1
- package/harness/opencode/agents/arka-chief-of-staff-afonso.md +1 -1
- package/harness/opencode/agents/arka-community-strategist-beatriz.md +1 -1
- package/harness/opencode/agents/arka-content-strategist-rafael.md +1 -1
- package/harness/opencode/agents/arka-conversion-strategist-ines.md +1 -1
- package/harness/opencode/agents/arka-coo-sofia.md +1 -1
- package/harness/opencode/agents/arka-copy-director-eduardo.md +1 -1
- package/harness/opencode/agents/arka-cqo-marta.md +1 -1
- package/harness/opencode/agents/arka-cto-marco.md +1 -1
- package/harness/opencode/agents/arka-design-ops-lead-iris.md +1 -1
- package/harness/opencode/agents/arka-ecom-director-ricardo.md +1 -1
- package/harness/opencode/agents/arka-knowledge-director-clara.md +1 -1
- package/harness/opencode/agents/arka-leadership-director-rodrigo.md +1 -1
- package/harness/opencode/agents/arka-marketing-director-luna.md +1 -1
- package/harness/opencode/agents/arka-ops-lead-daniel.md +1 -1
- package/harness/opencode/agents/arka-pm-director-carolina.md +1 -1
- package/harness/opencode/agents/arka-revops-lead-vicente.md +1 -1
- package/harness/opencode/agents/arka-saas-strategist-tiago.md +1 -1
- package/harness/opencode/agents/arka-sales-director-miguel.md +1 -1
- package/harness/opencode/agents/arka-strategy-director-tomas.md +1 -1
- package/harness/opencode/agents/arka-tech-director-francisca.md +1 -1
- package/harness/opencode/agents/arka-tech-lead-paulo.md +1 -1
- package/harness/opencode/agents/arka-video-producer-simao.md +1 -1
- package/harness/zed/.rules +1 -1
- package/knowledge/skills-manifest.json +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
package/THE-ARKAOS-GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The ArkaOS Guide
|
|
2
2
|
|
|
3
|
-
> v4.
|
|
3
|
+
> v4.48.0 — 89 agents, 17 departments, 332 skills, 297 commands, 19 ADRs.
|
|
4
4
|
> One file, everything you need to start. Generated by `scripts/guide_gen.py` — never hand-edited.
|
|
5
5
|
|
|
6
6
|
## What it is
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.48.0
|
package/core/egress/policy.py
CHANGED
|
@@ -28,6 +28,7 @@ import re
|
|
|
28
28
|
from dataclasses import dataclass, field
|
|
29
29
|
from datetime import datetime
|
|
30
30
|
from pathlib import Path
|
|
31
|
+
from typing import Any
|
|
31
32
|
|
|
32
33
|
from core.egress import allowlist, audit, redact
|
|
33
34
|
from core.governance.harness_scanner import secret_labels
|
|
@@ -42,7 +43,7 @@ class Finding:
|
|
|
42
43
|
# # | audit-unavailable | payload-not-text | guard-failure
|
|
43
44
|
token: str
|
|
44
45
|
|
|
45
|
-
def to_audit(self, salt: bytes = b"") -> dict:
|
|
46
|
+
def to_audit(self, salt: bytes = b"") -> dict[str, Any]:
|
|
46
47
|
return {
|
|
47
48
|
"kind": self.kind,
|
|
48
49
|
"token_sha16": (
|
|
@@ -64,7 +65,7 @@ class EgressDecision:
|
|
|
64
65
|
redacted_sha256: str = ""
|
|
65
66
|
audited: bool = False
|
|
66
67
|
|
|
67
|
-
def to_audit(self, salt: bytes = b"") -> dict:
|
|
68
|
+
def to_audit(self, salt: bytes = b"") -> dict[str, Any]:
|
|
68
69
|
return {
|
|
69
70
|
"allowed": self.allowed,
|
|
70
71
|
"destination": self.destination,
|
|
@@ -99,26 +100,43 @@ def evaluate(
|
|
|
99
100
|
) -> EgressDecision:
|
|
100
101
|
"""Judge one payload against the policy. Never raises.
|
|
101
102
|
|
|
102
|
-
``home`` scopes the home-path check
|
|
103
|
-
audit locations; ``now`` pins allowlist expiry
|
|
103
|
+
``home`` scopes the home-path check, the redaction config and the
|
|
104
|
+
default allowlist / audit locations; ``now`` pins allowlist expiry
|
|
105
|
+
for tests.
|
|
104
106
|
"""
|
|
105
107
|
destination = _safe_str(destination)
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
|
|
108
|
+
# ONCE, before any failure path, so no handler re-runs what
|
|
109
|
+
# failed. Named `digest`: `payload_digest` shadowed the public
|
|
110
|
+
# function here (QG D2 r12, Francisca M2).
|
|
111
|
+
digest = payload_digest(text) if isinstance(text, str) else ""
|
|
109
112
|
try:
|
|
110
113
|
decision = _judge(
|
|
111
114
|
text, destination, config_path, home, allowlist_path, now
|
|
112
115
|
)
|
|
113
116
|
except Exception as exc: # never-raises boundary — deny, not crash
|
|
114
|
-
decision =
|
|
115
|
-
allowed=False, destination=destination,
|
|
116
|
-
payload_sha256=payload_digest,
|
|
117
|
-
findings=[Finding("guard-failure", type(exc).__name__)],
|
|
118
|
-
)
|
|
117
|
+
decision = _guard_failure(destination, digest, exc)
|
|
119
118
|
return _audited(decision, home, audit_path, now)
|
|
120
119
|
|
|
121
120
|
|
|
121
|
+
def _guard_failure(
|
|
122
|
+
destination: str, digest: str, exc: BaseException
|
|
123
|
+
) -> EgressDecision:
|
|
124
|
+
return EgressDecision(
|
|
125
|
+
allowed=False, destination=destination, payload_sha256=digest,
|
|
126
|
+
findings=[Finding("guard-failure", type(exc).__name__)],
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def default_redaction_config_path(home: Path | None = None) -> Path:
|
|
131
|
+
"""The identifier list *home* implies.
|
|
132
|
+
|
|
133
|
+
Mirrors ``leak_scanner._DEFAULT_CONFIG_PATH`` for the real home, so
|
|
134
|
+
scoping by ``home`` never changes production behaviour — pinned by
|
|
135
|
+
``test_egress_policy.py`` rather than by this comment.
|
|
136
|
+
"""
|
|
137
|
+
return (home or Path.home()) / ".arkaos" / "redaction-clients.json"
|
|
138
|
+
|
|
139
|
+
|
|
122
140
|
def _safe_str(value: object) -> str:
|
|
123
141
|
try:
|
|
124
142
|
return str(value)
|
|
@@ -150,7 +168,7 @@ def _audited(
|
|
|
150
168
|
return decision
|
|
151
169
|
|
|
152
170
|
|
|
153
|
-
def enforce(text: object, destination: str, **kwargs) -> str:
|
|
171
|
+
def enforce(text: object, destination: str, **kwargs: Any) -> str:
|
|
154
172
|
"""The redacted text cleared to leave, or :class:`EgressDeniedError`."""
|
|
155
173
|
decision = evaluate(text, destination, **kwargs)
|
|
156
174
|
if not decision.allowed or decision.redacted_text is None:
|
|
@@ -167,41 +185,70 @@ def _judge(
|
|
|
167
185
|
now: datetime | None,
|
|
168
186
|
) -> EgressDecision:
|
|
169
187
|
if not isinstance(text, str):
|
|
170
|
-
return
|
|
171
|
-
allowed=False, destination=destination, payload_sha256="",
|
|
172
|
-
findings=[Finding("payload-not-text", type(text).__name__)],
|
|
173
|
-
)
|
|
188
|
+
return _not_text(destination, text)
|
|
174
189
|
decision = EgressDecision(
|
|
175
190
|
allowed=False, destination=destination,
|
|
176
|
-
payload_sha256=
|
|
191
|
+
payload_sha256=payload_digest(text),
|
|
177
192
|
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
# One scoped path for both layers: scoping only the redaction call
|
|
194
|
+
# left residual_identifiers reading the real machine's list
|
|
195
|
+
# (QG D2 r3, Francisca B1).
|
|
196
|
+
scoped = _scoped_config(config_path, home)
|
|
197
|
+
clean = _redacted(text, scoped)
|
|
198
|
+
if isinstance(clean, Finding):
|
|
199
|
+
decision.findings.append(clean)
|
|
181
200
|
return decision
|
|
182
201
|
_collect_findings(
|
|
183
|
-
decision, clean, destination,
|
|
202
|
+
decision, clean, destination, scoped, home, allowlist_path, now
|
|
184
203
|
)
|
|
185
204
|
if not decision.findings:
|
|
186
205
|
decision.allowed = True
|
|
187
206
|
decision.redacted_text = clean
|
|
188
|
-
decision.redacted_sha256 =
|
|
207
|
+
decision.redacted_sha256 = payload_digest(clean)
|
|
189
208
|
return decision
|
|
190
209
|
|
|
191
210
|
|
|
192
|
-
def
|
|
211
|
+
def _not_text(destination: str, text: object) -> EgressDecision:
|
|
212
|
+
return EgressDecision(
|
|
213
|
+
allowed=False, destination=destination, payload_sha256="",
|
|
214
|
+
findings=[Finding("payload-not-text", type(text).__name__)],
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def payload_digest(text: str) -> str:
|
|
193
219
|
"""Total over any str — surrogatepass, because a payload holding a
|
|
194
220
|
lone surrogate (routine from errors="surrogateescape" decoding or
|
|
195
221
|
json.loads of an escape) must be DIGESTIBLE to be denied with an
|
|
196
|
-
audit line (QG D1 r2 E-B1).
|
|
222
|
+
audit line (QG D1 r2 E-B1).
|
|
223
|
+
|
|
224
|
+
Public because callers outside this package need the same digest
|
|
225
|
+
the audit trail records; reaching for a private symbol made a D1
|
|
226
|
+
rename a silent runtime break downstream (QG D2 r1, Francisca M6).
|
|
227
|
+
"""
|
|
197
228
|
payload = text.encode("utf-8", errors="surrogatepass")
|
|
198
229
|
return hashlib.sha256(payload).hexdigest()
|
|
199
230
|
|
|
200
231
|
|
|
201
|
-
def
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
232
|
+
def _scoped_config(config_path: Path | None, home: Path | None) -> Path | None:
|
|
233
|
+
"""The redaction config *home* implies, unless one was named.
|
|
234
|
+
|
|
235
|
+
``home`` scoped ``allowlist_path`` and ``audit_path`` but NOT the
|
|
236
|
+
redaction config, so a caller passing ``home=`` and forgetting
|
|
237
|
+
``config_path`` judged paths against one home while redacting
|
|
238
|
+
against another (QG D2 r1, Francisca M7).
|
|
239
|
+
|
|
240
|
+
Called from inside ``_judge``, i.e. inside ``evaluate``'s try: the
|
|
241
|
+
same defaulting one frame up sat OUTSIDE it, and a non-Path home
|
|
242
|
+
turned the never-raises boundary into a TypeError — the very shape
|
|
243
|
+
QG D1 r2 F-M5 already closed once.
|
|
244
|
+
"""
|
|
245
|
+
if config_path is not None or home is None:
|
|
246
|
+
return config_path
|
|
247
|
+
return default_redaction_config_path(home)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _redacted(text: str, config_path: Path | None) -> str | Finding:
|
|
251
|
+
"""The clean text, or the finding that denies it.
|
|
205
252
|
|
|
206
253
|
A redaction that CRASHES proves nothing about the payload — same
|
|
207
254
|
posture as a missing config: denied, never allowlistable (QG D1
|
|
@@ -209,11 +256,16 @@ def _redacted(
|
|
|
209
256
|
"""
|
|
210
257
|
try:
|
|
211
258
|
clean, _counts = redact.redact(text, config_path)
|
|
212
|
-
|
|
259
|
+
# Annotated: redact() is untyped, so `clean` arrives as Any and
|
|
260
|
+
# the union return silently degrades to Any (mypy no-any-return,
|
|
261
|
+
# surfaced only with --follow-imports=skip —
|
|
262
|
+
# QG D2 r3, Francisca M3).
|
|
263
|
+
clean_text: str = clean
|
|
264
|
+
return clean_text
|
|
213
265
|
except redact.SanitizerConfigMissing:
|
|
214
|
-
return
|
|
266
|
+
return Finding("redaction-config-missing", "")
|
|
215
267
|
except Exception as exc:
|
|
216
|
-
return
|
|
268
|
+
return Finding("redaction-failed", type(exc).__name__)
|
|
217
269
|
|
|
218
270
|
|
|
219
271
|
def _collect_findings(
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Knowledge-base integrations that reach outside the machine.
|
|
2
|
+
|
|
3
|
+
Everything here goes through ``core.egress.policy`` before a byte
|
|
4
|
+
leaves. The package is deliberately absent from the critical path:
|
|
5
|
+
``tests/python/test_notebooklm_chokepoint.py`` asserts by import graph
|
|
6
|
+
that ``core/governance``, ``core/workflow`` and ``core/release`` never
|
|
7
|
+
import it, so an upstream tool breaking can stall research but never a
|
|
8
|
+
gate or a release.
|
|
9
|
+
"""
|