loki-mode 11.5.1 → 11.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -2
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/backlog.py +11 -2
- package/autonomy/lib/chat.sh +57 -1
- package/autonomy/lib/loki_yaml.py +8 -2
- package/autonomy/lib/workspace.py +267 -11
- package/autonomy/loki +327 -222
- package/autonomy/notification-checker.py +1 -1
- package/autonomy/trigger-server.py +185 -2
- package/autonomy/verify.sh +4 -0
- package/completions/_loki +4 -0
- package/completions/loki.bash +20 -2
- package/dashboard/__init__.py +3 -10
- package/dashboard/control.py +5 -435
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-CORE-VERBS.md +2 -6
- package/docs/CLI-REFERENCE.md +2 -1
- package/docs/COMPONENTS.md +0 -2
- package/docs/DEPLOY-PLAN.md +17 -8
- package/docs/EVALUATING.md +8 -0
- package/docs/INSTALLATION.md +1 -1
- package/docs/WORKSPACES.md +15 -2
- package/docs/authentication.md +19 -1
- package/docs/dev/architecture-reference.md +8 -0
- package/docs/dev/release-checklist.md +9 -8
- package/docs/enterprise/security.md +3 -234
- package/docs/sentry-intake.md +11 -0
- package/docs/v10/ARCHITECT-CUTS.md +304 -0
- package/docs/v10/CLI-MODERN.md +1 -1
- package/docs/v10/DECISIONS.md +5 -5
- package/docs/v10/ENGINE.md +735 -299
- package/docs/v10/GUARDS.md +16 -14
- package/docs/v10/GUIDE.md +5 -7
- package/docs/v10/PROGRESS.md +12 -1
- package/docs/v11/MARKET-SLICES.md +1 -5
- package/integrations/openclaw/README.md +20 -0
- package/integrations/vibe-kanban.md +12 -50
- package/loki-ts/dist/loki.js +1213 -1178
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +1090 -924
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/references/quality-control.md +1 -116
- package/schemas/loki-yaml.schema.json +5 -2
- package/skills/00-index.md +2 -2
- package/skills/artifacts.md +0 -22
- package/skills/production.md +2 -38
- package/src/policies/engine.js +41 -2
- package/src/policies/types.js +49 -0
- package/web-app/dist/assets/{AdminPage-Cbu3pXL8.js → AdminPage-S3BYeapm.js} +1 -1
- package/web-app/dist/assets/{Avatar-DGqGGcGx.js → Avatar-C1rHwLgn.js} +1 -1
- package/web-app/dist/assets/{Badge-Bhlipt6v.js → Badge-CzlnN5aQ.js} +1 -1
- package/web-app/dist/assets/{Button-CpN2sO61.js → Button-B1w5AeGC.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BqeDJwdL.js → CockpitPage-Dyeqjfkc.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DUieA2ba.js → ComparePage-C6y2GkGR.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DTWsYrOm.js → ErrorBoundary-Dg2fcGkR.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BU_B9X19.js → EvidenceReceiptPanel-CxbyjvTj.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DEZoLOsP.js → GitHubIssuesPanel-Dpys1xDb.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BEsnrq7Y.js → GitHubPRsPanel-CRVjWoFl.js} +1 -1
- package/web-app/dist/assets/{HomePage-BoUVuq7h.js → HomePage-BKnv-oYw.js} +2 -2
- package/web-app/dist/assets/{LoginPage-CmOED7vb.js → LoginPage-BGksmFRd.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DATZitrZ.js → MagicPage-OCvhp16M.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DGL1v0I-.js → MetricsPage-CJOJpXWC.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-C2WgOjZd.js → NotFoundPage-C04p3QvN.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BMi1tepj.js → ProjectPage-BRB8txsY.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-vc3y5YPh.js → ProjectsPage-CoUYeQEh.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-kbq0Ftvi.js → SettingsPage-BkjmJGfM.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-Bn6Q8Kbg.js → ShowcasePage-B4vU9TjQ.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-Basmhs_b.js → SystemSettingsPage-Z2jiVsni.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-BTqOc4TR.js → TeamsPage-Ulm8SISq.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-2P9002VL.js → TemplatesPage-C_7MM6Ey.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CAoSPBrg.js → TerminalOutput-Cumd7Tgs.js} +1 -1
- package/web-app/dist/assets/{activity-BcWVWCqU.js → activity-CZAUkbiY.js} +1 -1
- package/web-app/dist/assets/{bell-CYRqqgZ6.js → bell-BOvSXpEr.js} +1 -1
- package/web-app/dist/assets/{bot-CU7gdn3g.js → bot-DOTZxBYj.js} +1 -1
- package/web-app/dist/assets/{check-DLlCpz9V.js → check-BxpE0B5u.js} +1 -1
- package/web-app/dist/assets/{chevron-left-CE9Cb30C.js → chevron-left-D6KPvBOA.js} +1 -1
- package/web-app/dist/assets/{circle-alert-uou4bjua.js → circle-alert-Bajq86oe.js} +1 -1
- package/web-app/dist/assets/{clock-C_dSJcDX.js → clock-CnlHAVJc.js} +1 -1
- package/web-app/dist/assets/{cloud-DZ22ITF6.js → cloud-DjaymjwM.js} +1 -1
- package/web-app/dist/assets/{code-xml-BrJS0hhS.js → code-xml-BADEw2Ld.js} +1 -1
- package/web-app/dist/assets/{database-D2HOmxtl.js → database-B4aKb5Cq.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CQ1vK_6q.js → dollar-sign-DrldXpja.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-w2vpGm5d.js → file-code-corner-DVebDVR-.js} +1 -1
- package/web-app/dist/assets/{file-plus-DlF6wjkD.js → file-plus-BD-N_-Tl.js} +1 -1
- package/web-app/dist/assets/{globe-Dy3lBJg1.js → globe-C7ieInC-.js} +1 -1
- package/web-app/dist/assets/{hammer-C3xIiRXN.js → hammer-BSugKIji.js} +1 -1
- package/web-app/dist/assets/{index-4t-_IW2y.js → index-nLQgfvOn.js} +3 -3
- package/web-app/dist/assets/{layers-Y8Fs8qXI.js → layers-CHXxU2on.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CxgN1v4m.js → loader-circle-BEEz0LbD.js} +1 -1
- package/web-app/dist/assets/{lock-DFFNbXDs.js → lock-CzQGfcnE.js} +1 -1
- package/web-app/dist/assets/{package-5e6qCTUg.js → package-CcHYQLGd.js} +1 -1
- package/web-app/dist/assets/{plus-C0Go_ytj.js → plus-DdzgFEXn.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D4i-NW3o.js → refresh-cw-7x0HbH9Y.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-YlKkiUW6.js → rotate-ccw-DBahX1Sp.js} +1 -1
- package/web-app/dist/assets/{scroll-text-4qXOHTap.js → scroll-text-BB8y8a9Z.js} +1 -1
- package/web-app/dist/assets/{server-BB6zXNp9.js → server-CfkbW2MH.js} +1 -1
- package/web-app/dist/assets/{shield-alert-D4tzjB1H.js → shield-alert-DUgD8rBF.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DZiRwdFj.js → thumbs-up-DGoyY6QC.js} +1 -1
- package/web-app/dist/assets/{trash-2-Dv_LkRIK.js → trash-2-B6xrSUMr.js} +1 -1
- package/web-app/dist/assets/{trending-down-BJYp9PQe.js → trending-down-B6RGKTOx.js} +1 -1
- package/web-app/dist/assets/{trending-up-BTcXLklK.js → trending-up-B44DCrt1.js} +1 -1
- package/web-app/dist/assets/{upload-fcHqwOxr.js → upload-4kWm33ZY.js} +1 -1
- package/web-app/dist/assets/{usePolling-BeJYw_4L.js → usePolling-zkUtRQG6.js} +1 -1
- package/web-app/dist/assets/{user-BcDwUCsO.js → user-04cEVIe2.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/run.py +0 -63
- package/docs/openclaw-integration.md +0 -52
- package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
- package/docs/v10/MORNING-BRIEF-1003.md +0 -25
- package/docs/v10/MORNING-BRIEF.md +0 -52
- package/docs/v10/TODO.md +0 -35
- package/mcp/resources.py +0 -351
- package/mcp/tools.py +0 -200
package/docs/authentication.md
CHANGED
|
@@ -97,6 +97,20 @@ Scope hierarchy:
|
|
|
97
97
|
- `control` includes `write` and `read`
|
|
98
98
|
- `write` includes `read`
|
|
99
99
|
|
|
100
|
+
### Key Rotation and Revocation
|
|
101
|
+
|
|
102
|
+
Dashboard API keys (`/api/keys`) can be rotated with a grace period during which the old key stays valid (default 24 hours, `grace_period_hours`):
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
curl -X POST http://localhost:57374/api/keys/ci-pipeline/rotate \
|
|
106
|
+
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
107
|
+
-H "Content-Type: application/json" \
|
|
108
|
+
-d '{"grace_period_hours": 24}'
|
|
109
|
+
|
|
110
|
+
curl -X DELETE http://localhost:57374/api/keys/ci-pipeline \
|
|
111
|
+
-H "Authorization: Bearer $ADMIN_TOKEN"
|
|
112
|
+
```
|
|
113
|
+
|
|
100
114
|
### Roles
|
|
101
115
|
|
|
102
116
|
Predefined roles map to common access patterns:
|
|
@@ -177,7 +191,11 @@ Running with signature verification off provides no authentication security.
|
|
|
177
191
|
4. Provider redirects back with JWT
|
|
178
192
|
5. Dashboard validates JWT and grants access
|
|
179
193
|
|
|
180
|
-
OIDC-authenticated users
|
|
194
|
+
OIDC-authenticated users are NOT granted full access by default. The role is resolved from claims (see below) and its scopes are enforced through the same hierarchy as API tokens.
|
|
195
|
+
|
|
196
|
+
### OIDC Role Claims
|
|
197
|
+
|
|
198
|
+
Role claims are read case-insensitively; values may be a string, a space-separated string or a list. Sources: the claim named by `LOKI_OIDC_ROLES_CLAIM` (dotted paths such as `realm_access.roles` work), then `roles`, `groups`, `realm_access.roles` (Keycloak) and `cognito:groups` (AWS Cognito). Only values that exactly match a built-in role name (`admin`, `operator`, `viewer`, `auditor`) grant that role; other group names fall through to `LOKI_OIDC_DEFAULT_ROLE`. When several roles match, the highest privilege wins (`admin` > `operator` > `auditor` > `viewer`). An unset or unrecognized default falls back to `viewer`, never `admin`. When PyJWT and cryptography are installed, the signature (RS256/RS384/RS512), issuer, audience and expiry are verified against the issuer JWKS.
|
|
181
199
|
|
|
182
200
|
### Mixed Mode
|
|
183
201
|
|
|
@@ -105,3 +105,11 @@ These knobs together implement the RARV-C (closure) loop: findings -> override c
|
|
|
105
105
|
## Project memory across runs
|
|
106
106
|
|
|
107
107
|
extract_learnings_from_session (autonomy/run.sh) mirrors learnings and decisions into .loki/memory/learnings/project-*.jsonl. get_relevant_learnings adds a bounded newest-first project_memory list (15 entries, LOKI_PROJECT_MEMORY_MAX_CHARS, default 2000) to .loki/state/relevant-learnings.json at run start. LOKI_PROJECT_MEMORY=0 disables both. Test: tests/test-project-memory.sh.
|
|
108
|
+
|
|
109
|
+
## Verdicts, composite receipts and the autonomy ladder (v11.7.0)
|
|
110
|
+
- Two sets: receipt verdicts (`engine10/types.ts` Verdict: VERIFIED, PARTIAL, ALREADY_SATISFIED, SPEC_CONFLICT, FAILED) and run outcomes (`engine10/output.ts` Outcome adds BUDGET_STOP, BLOCKED, STALLED, CANCELLED; exit ladder EXIT). Only receipt verdicts are sealed.
|
|
111
|
+
- Composite: `features/speed/seal_group.ts` composeComposite/verifyComposite (schema `loki.v10.composite/1`), sealed by `loki verify --seal-composite <run_dir>`, signed with the existing `signReceipt`, capped by `capGroupVerdict`. Workspace runs seal it after integration.json.
|
|
112
|
+
- Autonomy ladder: `src/policies/engine.js` allowedActions(level) (propose = none, execute = pr, operate = pr + deploy; merge never). engine10 `supervisor.ts` prGate consults `src/policies/check.js`; `loki deploy --execute` consults it for `deploy` and fails closed. `loki trust` graduationAdvice is advisory and never writes the policy file.
|
|
113
|
+
- Parallel units: `route.ts` maybeRunGroup defaults to `features/speed/run_group.ts`, which freezes per-unit acceptance (`features/contract.ts`), runs units, merges with `engine10/integrate.ts` and seals once via sealGroup.
|
|
114
|
+
- Lessons: every sealed run appends a receipt fact (`LOKI_AUTO_LEARN_PR`, default on) outside the receipt body; `implement.ts` injects lessons and relevant learnings inside the untrusted-data fence; `loki memory brief --task T` prints the same block.
|
|
115
|
+
|
|
@@ -4,9 +4,10 @@ Moved out of CLAUDE.md (S-78) to keep the root file short. Updated in this
|
|
|
4
4
|
pass to remove two items that `docs/v10/DECISIONS.md` D25 and
|
|
5
5
|
`docs/LOKI-10-BUILD-PROMPT.md` section 1 have superseded:
|
|
6
6
|
- `git add -A` in step 4 is replaced with staging by name (repo rule, always).
|
|
7
|
-
- Per-merge pushing
|
|
8
|
-
approved
|
|
9
|
-
|
|
7
|
+
- Per-merge pushing and the D25 release trains are superseded by D96 (every
|
|
8
|
+
approved slice is a release; see `docs/v10/OPERATING-MODEL.md`). Waiting for
|
|
9
|
+
Tests and Security Audit green on that exact SHA still applies to any push
|
|
10
|
+
made outside the merge-gate.
|
|
10
11
|
"Wait for user approval before commit" from the old workflow is superseded
|
|
11
12
|
by the standing authorization in `docs/LOKI-10-BUILD-PROMPT.md` section 1
|
|
12
13
|
for sessions operating under that program; outside it, ask as normal.
|
|
@@ -116,13 +117,13 @@ rm -f loki-mode-*.tgz
|
|
|
116
117
|
```
|
|
117
118
|
If any check fails, do not release; fix the root cause first.
|
|
118
119
|
|
|
119
|
-
### 4. Commit and land (release
|
|
120
|
+
### 4. Commit and land (every approved slice is a release, D96)
|
|
120
121
|
|
|
121
122
|
Stage files by name (never `git add -A` or `git add .`), commit with the
|
|
122
|
-
repo-local `asklokesh` identity, no co-author.
|
|
123
|
-
|
|
124
|
-
Security Audit to go green on that
|
|
125
|
-
releasing. GitHub Actions then creates the tag, the GitHub Release, publishes
|
|
123
|
+
repo-local `asklokesh` identity, no co-author. The merge-gate merges approved
|
|
124
|
+
slices to main and main publishes to npm `next` (D96); for a manual push
|
|
125
|
+
(`git push origin main`), wait for Tests and Security Audit to go green on that
|
|
126
|
+
exact SHA before bumping VERSION and releasing. GitHub Actions then creates the tag, the GitHub Release, publishes
|
|
126
127
|
npm, builds/pushes Docker, and updates the Homebrew tap. Do not manually
|
|
127
128
|
create tags.
|
|
128
129
|
|
|
@@ -6,153 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
Loki Mode's security model follows a defense-in-depth approach. All security features are opt-in via environment variables, with sensible defaults that prioritize safety. When enterprise auth is not configured, the system operates in local-only mode with no network exposure.
|
|
8
8
|
|
|
9
|
-
## Authentication
|
|
9
|
+
## Authentication and Authorization
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The primary authentication method uses bearer tokens prefixed with `loki_`.
|
|
14
|
-
|
|
15
|
-
**Configuration:**
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# Enable token auth for the dashboard/control plane API
|
|
19
|
-
export LOKI_ENTERPRISE_AUTH=true
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Token Lifecycle:**
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# Create a new API key
|
|
26
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
27
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
28
|
-
-H "Content-Type: application/json" \
|
|
29
|
-
-d '{"name": "ci-pipeline", "role": "operator"}'
|
|
30
|
-
|
|
31
|
-
# Rotate a key with 24-hour grace period
|
|
32
|
-
curl -X POST http://localhost:57374/api/keys/ci-pipeline/rotate \
|
|
33
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
34
|
-
-H "Content-Type: application/json" \
|
|
35
|
-
-d '{"grace_period_hours": 24}'
|
|
36
|
-
|
|
37
|
-
# Revoke a key
|
|
38
|
-
curl -X DELETE http://localhost:57374/api/keys/ci-pipeline \
|
|
39
|
-
-H "Authorization: Bearer $ADMIN_TOKEN"
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**SDK Usage:**
|
|
43
|
-
|
|
44
|
-
Python:
|
|
45
|
-
```python
|
|
46
|
-
from loki_mode_sdk import AutonomiClient
|
|
47
|
-
|
|
48
|
-
client = AutonomiClient(
|
|
49
|
-
base_url="http://localhost:57374",
|
|
50
|
-
token="loki_your_token_here"
|
|
51
|
-
)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
TypeScript:
|
|
55
|
-
```typescript
|
|
56
|
-
import { AutonomiClient } from 'loki-mode-sdk';
|
|
57
|
-
|
|
58
|
-
const client = new AutonomiClient({
|
|
59
|
-
baseUrl: 'http://localhost:57374',
|
|
60
|
-
token: 'loki_your_token_here'
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### OIDC / SSO Integration
|
|
65
|
-
|
|
66
|
-
For organizations using identity providers (Okta, Auth0, Azure AD), Loki Mode supports OIDC-based authentication.
|
|
67
|
-
|
|
68
|
-
**Configuration:**
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
export LOKI_OIDC_ISSUER="https://your-idp.okta.com/oauth2/default"
|
|
72
|
-
export LOKI_OIDC_CLIENT_ID="your-client-id"
|
|
73
|
-
# Optional: audience override (defaults to LOKI_OIDC_CLIENT_ID)
|
|
74
|
-
export LOKI_OIDC_AUDIENCE="your-api-audience"
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The system validates OIDC bearer tokens (presented as `Authorization: Bearer <jwt>`)
|
|
78
|
-
against the issuer's JWKS endpoint. When PyJWT + cryptography are installed, the
|
|
79
|
-
JWT signature is cryptographically verified (RS256/RS384/RS512) along with the
|
|
80
|
-
issuer, audience, and expiry. Without PyJWT, tokens are rejected unless
|
|
81
|
-
`LOKI_OIDC_SKIP_SIGNATURE_VERIFY=true` is set explicitly (insecure, local testing
|
|
82
|
-
only).
|
|
83
|
-
|
|
84
|
-
**Claims-to-roles mapping:**
|
|
85
|
-
|
|
86
|
-
On a valid token, role/group claims are mapped to the four built-in Loki roles
|
|
87
|
-
(`admin`, `operator`, `viewer`, `auditor`). The resolved role's scopes are then
|
|
88
|
-
enforced through the same scope hierarchy used for API tokens. OIDC users are
|
|
89
|
-
NOT granted full access by default.
|
|
90
|
-
|
|
91
|
-
Recognized claim sources (case-insensitive; values may be a string,
|
|
92
|
-
space-separated string, or list):
|
|
93
|
-
|
|
94
|
-
| Claim | Provider |
|
|
95
|
-
|-------|----------|
|
|
96
|
-
| value of `LOKI_OIDC_ROLES_CLAIM` (supports dotted paths, e.g. `realm_access.roles`) | configurable |
|
|
97
|
-
| `roles` | generic |
|
|
98
|
-
| `groups` | generic |
|
|
99
|
-
| `realm_access.roles` | Keycloak |
|
|
100
|
-
| `cognito:groups` | AWS Cognito |
|
|
101
|
-
|
|
102
|
-
Only claim values that exactly match a built-in role name (`admin`, `operator`,
|
|
103
|
-
`viewer`, `auditor`) grant that role. Arbitrary group names (common in `groups`
|
|
104
|
-
or `cognito:groups`) do not map to a role and fall through to the default.
|
|
105
|
-
|
|
106
|
-
When multiple recognized roles are present, the highest-privilege match wins
|
|
107
|
-
(precedence: `admin` > `operator` > `auditor` > `viewer`).
|
|
108
|
-
|
|
109
|
-
**Default role (when no recognized role claim is present):**
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
# Defaults to the least-privileged role (viewer). Never admin.
|
|
113
|
-
export LOKI_OIDC_DEFAULT_ROLE="viewer"
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
If `LOKI_OIDC_DEFAULT_ROLE` is unset or set to an unrecognized value, it falls
|
|
117
|
-
back to `viewer`. The default is never `admin` / full access.
|
|
118
|
-
|
|
119
|
-
## Authorization
|
|
120
|
-
|
|
121
|
-
### Role-Based Access Control
|
|
122
|
-
|
|
123
|
-
Four built-in roles provide scoped access:
|
|
124
|
-
|
|
125
|
-
| Role | Scope | Permissions |
|
|
126
|
-
|------|-------|-------------|
|
|
127
|
-
| `admin` | Full control | Create/delete tenants, manage API keys, configure policies, all operator/viewer/auditor permissions |
|
|
128
|
-
| `operator` | Execution | Start/cancel runs, create/update projects and tasks, read all resources |
|
|
129
|
-
| `viewer` | Read-only | Read projects, runs, tasks, status. No write or delete operations |
|
|
130
|
-
| `auditor` | Audit access | Read audit logs, verify chain integrity, generate compliance reports. No execution permissions |
|
|
131
|
-
|
|
132
|
-
**Scope Hierarchy:**
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
admin > operator > viewer
|
|
136
|
-
admin > auditor
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Admin inherits all permissions. Operator inherits viewer permissions. Auditor is a separate branch with read-only access to audit data.
|
|
140
|
-
|
|
141
|
-
**API Key Scopes:**
|
|
142
|
-
|
|
143
|
-
API keys are created with a role assignment:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
# Create a viewer key for monitoring dashboards
|
|
147
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
148
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
149
|
-
-d '{"name": "grafana-reader", "role": "viewer"}'
|
|
150
|
-
|
|
151
|
-
# Create an operator key for CI pipelines
|
|
152
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
153
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
154
|
-
-d '{"name": "github-actions", "role": "operator"}'
|
|
155
|
-
```
|
|
11
|
+
Token auth (`LOKI_ENTERPRISE_AUTH`), key rotation with a 24-hour grace period, OIDC/SSO claim mapping and the default viewer role are documented in [authentication.md](../authentication.md). Roles (`admin`, `operator`, `viewer`, `auditor`), scope hierarchy and API key scopes are in [authorization.md](../authorization.md).
|
|
156
12
|
|
|
157
13
|
## API Security
|
|
158
14
|
|
|
@@ -221,94 +77,7 @@ This is a deliberate fail-closed design. Invalid or missing signatures always re
|
|
|
221
77
|
|
|
222
78
|
## Audit Logging
|
|
223
79
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
Audit logs use SHA-256 hash chains for tamper evidence. Each entry's hash depends on the previous entry's hash, creating an immutable chain from the genesis record.
|
|
227
|
-
|
|
228
|
-
**JavaScript Audit (Agent Actions):**
|
|
229
|
-
|
|
230
|
-
```
|
|
231
|
-
.loki/audit/audit.jsonl
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Each entry:
|
|
235
|
-
```json
|
|
236
|
-
{
|
|
237
|
-
"seq": 42,
|
|
238
|
-
"timestamp": "2026-02-21T10:00:00.000Z",
|
|
239
|
-
"who": "agent-1",
|
|
240
|
-
"what": "file_write",
|
|
241
|
-
"where": "src/app.js",
|
|
242
|
-
"why": "implement feature",
|
|
243
|
-
"previousHash": "abc123...",
|
|
244
|
-
"hash": "def456..."
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
**Python Audit (Dashboard API):**
|
|
249
|
-
|
|
250
|
-
```
|
|
251
|
-
~/.loki/dashboard/audit/audit-2026-02-21.jsonl
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Each entry:
|
|
255
|
-
```json
|
|
256
|
-
{
|
|
257
|
-
"timestamp": "2026-02-21T10:00:00.000Z",
|
|
258
|
-
"action": "create",
|
|
259
|
-
"resource_type": "project",
|
|
260
|
-
"resource_id": "proj-1",
|
|
261
|
-
"user_id": "admin",
|
|
262
|
-
"success": true,
|
|
263
|
-
"_integrity_hash": "abc123..."
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### Chain Verification
|
|
268
|
-
|
|
269
|
-
JavaScript:
|
|
270
|
-
```javascript
|
|
271
|
-
const audit = require('./src/audit');
|
|
272
|
-
audit.init('/path/to/project');
|
|
273
|
-
const result = audit.verifyChain();
|
|
274
|
-
// { valid: true, entries: 1542, brokenAt: null, error: null }
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Python:
|
|
278
|
-
```python
|
|
279
|
-
from dashboard.audit import verify_log_integrity
|
|
280
|
-
result = verify_log_integrity("/path/to/audit-2026-02-21.jsonl")
|
|
281
|
-
# {"valid": True, "entries_checked": 1542, "first_tampered_line": None}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
API:
|
|
285
|
-
```bash
|
|
286
|
-
curl http://localhost:57374/api/audit/verify \
|
|
287
|
-
-H "Authorization: Bearer $TOKEN"
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Syslog Forwarding
|
|
291
|
-
|
|
292
|
-
Forward audit events to a centralized syslog server for SIEM integration:
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
export LOKI_AUDIT_SYSLOG_HOST="syslog.company.com"
|
|
296
|
-
export LOKI_AUDIT_SYSLOG_PORT="514" # default
|
|
297
|
-
export LOKI_AUDIT_SYSLOG_PROTO="udp" # or "tcp"
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Security-relevant actions (`delete`, `kill`, `stop`, `login`, `logout`, `create_token`, `revoke_token`) are logged at `WARNING` level. All other actions are logged at `INFO` level.
|
|
301
|
-
|
|
302
|
-
Syslog forwarding is fire-and-forget -- failures never block the main audit write path.
|
|
303
|
-
|
|
304
|
-
### Log Rotation
|
|
305
|
-
|
|
306
|
-
```bash
|
|
307
|
-
export LOKI_AUDIT_MAX_SIZE_MB="10" # Rotate when file exceeds this size
|
|
308
|
-
export LOKI_AUDIT_MAX_FILES="10" # Keep this many rotated files
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
Date-based log files (`audit-YYYY-MM-DD.jsonl`) are automatically rotated when they exceed the size limit. Old files are removed when the count exceeds the maximum.
|
|
80
|
+
Hash-chained audit logs, chain verification, syslog forwarding (`LOKI_AUDIT_SYSLOG_*`) and rotation (`LOKI_AUDIT_MAX_SIZE_MB`, `LOKI_AUDIT_MAX_FILES`) are documented in [audit-logging.md](../audit-logging.md).
|
|
312
81
|
|
|
313
82
|
## Data Residency
|
|
314
83
|
|
package/docs/sentry-intake.md
CHANGED
|
@@ -11,3 +11,14 @@ From a URL (needs `SENTRY_AUTH_TOKEN`; without it nothing is fetched):
|
|
|
11
11
|
SENTRY_AUTH_TOKEN=... loki start https://sentry.io/organizations/acme/issues/4001/
|
|
12
12
|
|
|
13
13
|
The token is sent only to the Sentry host through a curl config on stdin, never on argv, and is never printed. Implementation: `autonomy/issue-providers.sh` (`normalize_sentry_json`).
|
|
14
|
+
|
|
15
|
+
## Webhook: self-healing entry point
|
|
16
|
+
|
|
17
|
+
`autonomy/trigger-server.py` accepts `POST /sentry`, a Sentry integration webhook authenticated by Sentry's own HMAC (`sentry-hook-signature`, hex HMAC-SHA256 of the body).
|
|
18
|
+
|
|
19
|
+
1. Set the client secret: `LOKI_SENTRY_WEBHOOK_SECRET` (or `SENTRY_CLIENT_SECRET`). It must differ from the GitHub webhook secret and the API token. With no secret the route answers 503 and nothing is enqueued.
|
|
20
|
+
2. Start the server: `python3 autonomy/trigger-server.py --port 8080` and point the Sentry alert webhook at `/sentry`.
|
|
21
|
+
3. A valid alert is normalized with `normalize_sentry_json` and enqueues `loki start "<brief>" --pr --detach`. A bad signature gets 401.
|
|
22
|
+
|
|
23
|
+
The output is a receipt-gated PR only, never a deploy. Whether the PR opens is still decided by the policy file (`autonomy`).
|
|
24
|
+
|