artifacty 0.11.1 → 0.13.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/CLAUDE.md +10 -4
- package/README.md +164 -24
- package/SECURITY.md +25 -16
- package/docs/artifact-schema-v1.md +73 -50
- package/docs/central-team-deployment-design.md +56 -52
- package/docs/integrations.md +29 -25
- package/docs/mcp-public-api.md +75 -57
- package/docs/network-sharing.md +8 -8
- package/docs/release-checklist.md +29 -13
- package/docs/roadmap-design.md +145 -133
- package/docs/sarif-csv-artifact-plan.md +25 -26
- package/docs/threat-model.md +121 -100
- package/docs/upgrade-backups.md +89 -0
- package/docs/writing-style.md +56 -0
- package/package.json +5 -3
- package/src/cli.js +78 -3
- package/src/lib/backup.js +19 -6
- package/src/lib/doctor.js +1 -1
- package/src/lib/i18n.js +142 -0
- package/src/lib/network-policy.js +234 -0
- package/src/lib/render.js +142 -28
- package/src/lib/sample-content.js +191 -0
- package/src/lib/samples.js +74 -0
- package/src/lib/share-links.js +136 -0
- package/src/lib/storage.js +458 -45
- package/src/lib/upgrade-backup.js +417 -0
- package/src/mcp-server.js +18 -6
- package/src/server.js +198 -7
package/docs/roadmap-design.md
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
# Artifacty Enhancement Roadmap Design
|
|
2
2
|
|
|
3
3
|
This document specifies the design for the next set of Artifacty capabilities.
|
|
4
|
-
Each feature
|
|
5
|
-
|
|
6
|
-
feature follows the existing architecture rules: shared behavior lives in
|
|
7
|
-
`src/lib/*`, the HTTP, CLI, and MCP surfaces stay thin adapters, versions stay
|
|
8
|
-
append-only, artifact content stays untrusted, and no new runtime dependency is
|
|
9
|
-
added unless the section says so explicitly.
|
|
4
|
+
Each feature can be implemented and tested independently. Features are grouped
|
|
5
|
+
by theme and listed in the recommended priority order.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
Every feature follows these architecture rules:
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
- Put shared behavior in `src/lib/*`.
|
|
10
|
+
- Keep the HTTP, CLI, and MCP interfaces as thin adapters.
|
|
11
|
+
- Keep versions append-only.
|
|
12
|
+
- Treat artifact content as untrusted.
|
|
13
|
+
- Add no runtime dependency unless the section explicitly permits it.
|
|
14
|
+
|
|
15
|
+
Status recorded on 2026-09-04: all sections below were implemented, and
|
|
16
|
+
`STORE_VERSION` was `8`. The original planning text follows.
|
|
17
|
+
|
|
18
|
+
Store schema changes increase `STORE_VERSION` (originally `4`). They use the
|
|
19
|
+
existing `ensureColumn` / `CREATE TABLE IF NOT EXISTS` migration path. Older
|
|
20
|
+
stores upgrade on first access.
|
|
16
21
|
|
|
17
22
|
## Contents
|
|
18
23
|
|
|
@@ -78,15 +83,15 @@ MCP tools map the same `code` into `isError: true` results with the code in
|
|
|
78
83
|
|
|
79
84
|
### 1.4 Feature flags
|
|
80
85
|
|
|
81
|
-
|
|
82
|
-
environment variable
|
|
83
|
-
`
|
|
86
|
+
If new behavior changes an existing installation's defaults, control it with an
|
|
87
|
+
environment variable. Each section lists its variable. `artifacty doctor` and
|
|
88
|
+
`artifacty_info` report every flag.
|
|
84
89
|
|
|
85
90
|
### 1.5 Testing
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
`server.test.js`, `mcp-server.test.js`, `cli.test.js`, `converters.test.js
|
|
89
|
-
|
|
92
|
+
Add tests for each feature to the matching suite: `storage.test.js`,
|
|
93
|
+
`server.test.js`, `mcp-server.test.js`, `cli.test.js`, or `converters.test.js`.
|
|
94
|
+
If the behavior is externally visible, add a smoke assertion in `npm run smoke`.
|
|
90
95
|
|
|
91
96
|
---
|
|
92
97
|
|
|
@@ -94,9 +99,8 @@ where behavior is externally visible, a smoke assertion in `npm run smoke`.
|
|
|
94
99
|
|
|
95
100
|
### Problem
|
|
96
101
|
|
|
97
|
-
Artifacts are linked only through shared tags.
|
|
98
|
-
|
|
99
|
-
the tag scheme used by the publishing agent.
|
|
102
|
+
Artifacts are linked only through shared tags. To find a handoff, its review,
|
|
103
|
+
and its release notes, users must know the publishing agent's tag scheme.
|
|
100
104
|
|
|
101
105
|
### Goals
|
|
102
106
|
|
|
@@ -148,10 +152,10 @@ listRelations(store, id, { direction: "out" | "in" | "both", relation })
|
|
|
148
152
|
```
|
|
149
153
|
|
|
150
154
|
`createArtifact` and `updateArtifact` accept an optional `relations` array
|
|
151
|
-
(`[{ toId, relation }]`)
|
|
152
|
-
returns `relations: { outgoing: [...], incoming: [...] }
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
(`[{ toId, relation }]`). This lets an agent add links in the same call.
|
|
156
|
+
`getArtifact` returns `relations: { outgoing: [...], incoming: [...] }`. Each
|
|
157
|
+
entry includes `toArtifactSummary` for the related artifact. If the target row
|
|
158
|
+
no longer exists, the entry includes `missing: true`.
|
|
155
159
|
|
|
156
160
|
### Surfaces
|
|
157
161
|
|
|
@@ -165,8 +169,8 @@ target row no longer exists.
|
|
|
165
169
|
### Handoff prompt integration
|
|
166
170
|
|
|
167
171
|
The `artifacty_handoff` and `artifacty_review` prompt templates instruct the
|
|
168
|
-
agent to pass `relations: [{ toId: <source>, relation: "derived-from" }]
|
|
169
|
-
graph
|
|
172
|
+
agent to pass `relations: [{ toId: <source>, relation: "derived-from" }]`. The
|
|
173
|
+
agent can then add the graph links without user intervention.
|
|
170
174
|
|
|
171
175
|
### Tests
|
|
172
176
|
|
|
@@ -217,10 +221,10 @@ Event types: `artifact.created`, `artifact.updated`, `artifact.archived`,
|
|
|
217
221
|
`artifact.restored`, `artifact.relation.added`, `artifact.comment.added`,
|
|
218
222
|
`artifact.version.repaired`, `artifact.version.deleted`.
|
|
219
223
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
`events.publish(eventFromAudit(row))`.
|
|
223
|
-
uncommitted transactions.
|
|
224
|
+
The storage layer derives events from audit rows. `insertAuditRecord` becomes
|
|
225
|
+
the single place that starts event publication. After the transaction commits,
|
|
226
|
+
the storage layer calls `events.publish(eventFromAudit(row))`. It must not
|
|
227
|
+
publish events for uncommitted transactions.
|
|
224
228
|
|
|
225
229
|
### Persistence
|
|
226
230
|
|
|
@@ -245,11 +249,13 @@ prune on insert.
|
|
|
245
249
|
|
|
246
250
|
`GET /api/events` with `Accept: text/event-stream`.
|
|
247
251
|
|
|
248
|
-
Query filters
|
|
249
|
-
token rules as other API routes.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
Query filters are `type`, `tag`, `artifactId`, and `sourceAgent`. Authentication
|
|
253
|
+
uses the same token rules as other API routes. The server sends a heartbeat
|
|
254
|
+
comment every 25 seconds. If a client connects with `Last-Event-ID`, the server
|
|
255
|
+
replays events from that sequence.
|
|
256
|
+
|
|
257
|
+
`ARTIFACTY_SSE_MAX_CLIENTS` limits concurrent connections per server (default
|
|
258
|
+
64). The server returns `503` for connections above this limit.
|
|
253
259
|
|
|
254
260
|
### Webhooks
|
|
255
261
|
|
|
@@ -272,8 +278,9 @@ CREATE TABLE IF NOT EXISTS webhooks (
|
|
|
272
278
|
- Delivery: `POST` JSON body, headers `X-Artifacty-Event`,
|
|
273
279
|
`X-Artifacty-Delivery`, `X-Artifacty-Signature: sha256=<hmac>` over the raw
|
|
274
280
|
body using the secret shown once at creation.
|
|
275
|
-
- Retry: 3 attempts with 2s, 10s, 60s
|
|
276
|
-
|
|
281
|
+
- Retry: 3 attempts with delays of 2s, 10s, and 60s. After 20 consecutive
|
|
282
|
+
failures, the server disables the webhook. It writes a
|
|
283
|
+
`webhook-deliver-failed` audit row.
|
|
277
284
|
- SSRF guard: the target URL must be `http` or `https`; loopback, link-local,
|
|
278
285
|
and private ranges are rejected unless `ARTIFACTY_WEBHOOK_ALLOW_PRIVATE=true`.
|
|
279
286
|
Redirects are not followed.
|
|
@@ -290,10 +297,10 @@ Routes: `GET/POST /api/webhooks`, `DELETE /api/webhooks/:id`,
|
|
|
290
297
|
`notifications/resources/updated` with the URI.
|
|
291
298
|
- The stdio bridge forwards notifications received from the remote `/mcp`
|
|
292
299
|
stream to the local client.
|
|
293
|
-
- New tool `artifacty_wait`
|
|
294
|
-
|
|
295
|
-
`{ timedOut: true }`.
|
|
296
|
-
long
|
|
300
|
+
- New tool `artifacty_wait` accepts `{ artifactId?, tag?, type?, timeoutMs }`.
|
|
301
|
+
It waits up to `timeoutMs` (max 120000). It returns the first matching event
|
|
302
|
+
or `{ timedOut: true }`. Clients without subscription support can use this
|
|
303
|
+
tool for long polling.
|
|
297
304
|
|
|
298
305
|
### CLI
|
|
299
306
|
|
|
@@ -311,17 +318,17 @@ MCP subscribe round trip through the HTTP transport, `artifacty_wait` timeout.
|
|
|
311
318
|
|
|
312
319
|
### Problem
|
|
313
320
|
|
|
314
|
-
|
|
315
|
-
versions 4 and 5. The
|
|
316
|
-
|
|
321
|
+
If two agents read version 3 and both call `artifacty_update`, they produce
|
|
322
|
+
versions 4 and 5. The latest version then omits the first agent's work without
|
|
323
|
+
reporting a conflict.
|
|
317
324
|
|
|
318
325
|
### Design
|
|
319
326
|
|
|
320
327
|
- Every artifact response exposes `latestVersion` (already present) and an
|
|
321
328
|
`etag` string equal to `"<id>:<latestVersion>"`.
|
|
322
|
-
- `updateArtifact` accepts `expectedVersion` (number).
|
|
323
|
-
transaction,
|
|
324
|
-
`VersionConflictError`
|
|
329
|
+
- `updateArtifact` accepts `expectedVersion` (number). In the existing
|
|
330
|
+
transaction, check whether `artifact.latestVersion !== expectedVersion`.
|
|
331
|
+
If the versions differ, throw `VersionConflictError` with `latestVersion`. Write an
|
|
325
332
|
`update-conflict` audit row.
|
|
326
333
|
- HTTP: `POST /api/artifacts/:id/versions` (and the browser edit form) accept
|
|
327
334
|
`If-Match: "<etag>"` or body `expectedVersion`. Conflict returns `409` with
|
|
@@ -332,9 +339,9 @@ from the "latest" view.
|
|
|
332
339
|
`artifacty_get` output already carries `latestVersion`; the tool description
|
|
333
340
|
tells agents to pass it back.
|
|
334
341
|
- CLI: `artifacty update --expected-version N`.
|
|
335
|
-
- Browser editor: hidden field
|
|
336
|
-
|
|
337
|
-
|
|
342
|
+
- Browser editor: use a hidden field for the version being edited. On `409`,
|
|
343
|
+
keep the unsaved text and show a banner. The banner links to a diff between
|
|
344
|
+
the edited base version and the new latest version.
|
|
338
345
|
|
|
339
346
|
`expectedVersion` is optional so existing clients keep working. A future
|
|
340
347
|
`ARTIFACTY_REQUIRE_EXPECTED_VERSION=true` flag can make it mandatory for API
|
|
@@ -352,8 +359,8 @@ with matching version, `If-Match` header parsing including weak validators,
|
|
|
352
359
|
|
|
353
360
|
### Problem
|
|
354
361
|
|
|
355
|
-
Feedback on an artifact
|
|
356
|
-
|
|
362
|
+
Feedback on an artifact requires a new version or a separate review artifact.
|
|
363
|
+
Users cannot add a short note to a specific version.
|
|
357
364
|
|
|
358
365
|
### Data model
|
|
359
366
|
|
|
@@ -382,18 +389,18 @@ CREATE INDEX IF NOT EXISTS idx_comments_artifact ON artifact_comments(artifact_i
|
|
|
382
389
|
formats, `{ "path": "$.runs[0].results[3]" }` for JSON/SARIF, `{ "row": 7 }`
|
|
383
390
|
for CSV. Anchors are hints for rendering and are not validated against
|
|
384
391
|
content.
|
|
385
|
-
- `body` is Markdown
|
|
386
|
-
|
|
392
|
+
- `body` is Markdown with a 16 KB size limit. The renderer uses the same
|
|
393
|
+
sanitized Markdown pipeline as artifact content.
|
|
387
394
|
- Comments are soft-deleted; the audit log keeps the action.
|
|
388
395
|
- Threads are one level deep (`parent_id` points to a root comment).
|
|
389
396
|
|
|
390
397
|
### Review state
|
|
391
398
|
|
|
392
|
-
|
|
393
|
-
`
|
|
394
|
-
`POST /api/artifacts/:id/review-status
|
|
395
|
-
|
|
396
|
-
|
|
399
|
+
Add a `reviewStatus` column to `artifacts`. Its values are `none`, `pending`,
|
|
400
|
+
`changes-requested`, and `approved`. Set it explicitly through
|
|
401
|
+
`POST /api/artifacts/:id/review-status`. If a new version is appended after an
|
|
402
|
+
approval, reset the status to `pending` and record the reset in audit metadata.
|
|
403
|
+
This design does not include rules for multiple approvers.
|
|
397
404
|
|
|
398
405
|
### Surfaces
|
|
399
406
|
|
|
@@ -420,18 +427,19 @@ sanitization of comment bodies.
|
|
|
420
427
|
|
|
421
428
|
### Problem
|
|
422
429
|
|
|
423
|
-
FTS5 handles keyword queries.
|
|
424
|
-
|
|
430
|
+
FTS5 handles keyword queries. A natural-language question can miss relevant
|
|
431
|
+
results if it uses different words. For example: "the analysis of last week's
|
|
432
|
+
failed deploy".
|
|
425
433
|
|
|
426
434
|
### Design principles
|
|
427
435
|
|
|
428
|
-
- No mandatory dependency and no bundled model.
|
|
429
|
-
|
|
430
|
-
-
|
|
431
|
-
|
|
432
|
-
-
|
|
433
|
-
|
|
434
|
-
|
|
436
|
+
- No mandatory dependency and no bundled model. A configurable provider
|
|
437
|
+
supplies embeddings.
|
|
438
|
+
- If semantic search is disabled or unavailable, keep the existing search
|
|
439
|
+
behavior.
|
|
440
|
+
- Store vectors in SQLite as BLOBs. Compute similarity in JavaScript. This
|
|
441
|
+
supports the expected store size of tens of thousands of artifacts without
|
|
442
|
+
a native vector extension.
|
|
435
443
|
|
|
436
444
|
### Provider interface (`src/lib/embeddings.js`)
|
|
437
445
|
|
|
@@ -472,17 +480,18 @@ The embedded text is `title + tags + metadata summary + first
|
|
|
472
480
|
ARTIFACTY_EMBEDDINGS_MAX_CHARS (default 8000) characters of the latest version`.
|
|
473
481
|
Binary formats (`image`, `video`) embed metadata only.
|
|
474
482
|
|
|
475
|
-
|
|
476
|
-
after each create
|
|
477
|
-
|
|
483
|
+
Run indexing through the existing background module (`src/lib/background.js`)
|
|
484
|
+
after each create or update. Writes must not wait for a network call. Log
|
|
485
|
+
failures. Use `artifacty index rebuild --embeddings` to retry indexing.
|
|
478
486
|
|
|
479
487
|
### Query
|
|
480
488
|
|
|
481
489
|
`GET /api/artifacts?q=...&mode=semantic|keyword|hybrid`.
|
|
482
490
|
|
|
483
491
|
- `keyword`: current FTS5 path.
|
|
484
|
-
- `semantic`: embed the query
|
|
485
|
-
configured provider
|
|
492
|
+
- `semantic`: embed the query. Calculate cosine similarity across all vectors
|
|
493
|
+
for the configured provider and model. Return the top `limit` results after
|
|
494
|
+
`offset`.
|
|
486
495
|
- `hybrid` (default when a provider is configured): reciprocal rank fusion of
|
|
487
496
|
keyword and semantic rankings, `k = 60`.
|
|
488
497
|
|
|
@@ -504,11 +513,11 @@ Completes the "Future Extensions" list in `docs/sarif-csv-artifact-plan.md`.
|
|
|
504
513
|
|
|
505
514
|
### Design
|
|
506
515
|
|
|
507
|
-
-
|
|
508
|
-
|
|
509
|
-
- SARIF viewer: level filter chips (`error`, `warning`, `note`)
|
|
510
|
-
filter
|
|
511
|
-
|
|
516
|
+
- The server renders a limited set of results. `src/client/viewer.js` adds
|
|
517
|
+
browser controls that use the data already in the table.
|
|
518
|
+
- SARIF viewer: add level filter chips (`error`, `warning`, `note`) and a rule
|
|
519
|
+
id text filter. Allow sorting by level, rule, or location. Filter only the
|
|
520
|
+
rendered results. Show a notice if the result set was truncated.
|
|
512
521
|
- CSV viewer: click column header to sort; per-column contains filter; row
|
|
513
522
|
count shown.
|
|
514
523
|
- Download: `GET /artifacts/:id/export?format=csv&filter=...&sort=...` for CSV,
|
|
@@ -529,10 +538,10 @@ byte cap, viewer script has no inline event handlers (CSP compatibility).
|
|
|
529
538
|
|
|
530
539
|
### Design
|
|
531
540
|
|
|
532
|
-
-
|
|
533
|
-
`createdBefore`, `reviewStatus`, `relatedTo`, and `mode` (search).
|
|
534
|
-
query
|
|
535
|
-
reuse the same `listArtifactsPage` filters.
|
|
541
|
+
- Add list filters for `artifactType`, `publisher`, `createdAfter`,
|
|
542
|
+
`createdBefore`, `reviewStatus`, `relatedTo`, and `mode` (search). Put the
|
|
543
|
+
filters in query strings so users can share URLs. The CLI and MCP list
|
|
544
|
+
interfaces reuse the same `listArtifactsPage` filters.
|
|
536
545
|
- Saved views:
|
|
537
546
|
|
|
538
547
|
```sql
|
|
@@ -547,8 +556,9 @@ CREATE TABLE IF NOT EXISTS saved_views (
|
|
|
547
556
|
);
|
|
548
557
|
```
|
|
549
558
|
|
|
550
|
-
In single-user mode (no users table rows) views are global
|
|
551
|
-
|
|
559
|
+
In single-user mode (no users table rows), views are global. In team mode,
|
|
560
|
+
each view belongs to a user. Mark a view as `shared` to make it appear for
|
|
561
|
+
everyone.
|
|
552
562
|
|
|
553
563
|
- Routes: `GET/POST /api/views`, `DELETE /api/views/:id`; browser sidebar
|
|
554
564
|
lists views and a "Save current filters" action.
|
|
@@ -572,12 +582,12 @@ Artifacts, audit rows, and (after section 3) events grow without bound.
|
|
|
572
582
|
|
|
573
583
|
### Design
|
|
574
584
|
|
|
575
|
-
|
|
576
|
-
`src/lib/background.js` every `ARTIFACTY_RETENTION_INTERVAL`
|
|
577
|
-
|
|
585
|
+
Define retention rules in a policy. A background sweep in
|
|
586
|
+
`src/lib/background.js` evaluates the policy every `ARTIFACTY_RETENTION_INTERVAL`
|
|
587
|
+
(default 1h). Run `artifacty retention run` to evaluate it on demand.
|
|
578
588
|
|
|
579
|
-
|
|
580
|
-
|
|
589
|
+
Store the configuration as JSON in the `meta` table under `retention_policy`.
|
|
590
|
+
Edit it through `/admin/retention` or `artifacty retention set`:
|
|
581
591
|
|
|
582
592
|
```json
|
|
583
593
|
{
|
|
@@ -603,8 +613,8 @@ Semantics:
|
|
|
603
613
|
- `auditRetentionDays`: audit rows older than the window are deleted, except
|
|
604
614
|
`version-repair`, `version-delete`, `retention-purge`, and
|
|
605
615
|
`owner-change` which are kept indefinitely.
|
|
606
|
-
- Every sweep writes a summary row (`retention-sweep`)
|
|
607
|
-
|
|
616
|
+
- Every sweep writes a summary row (`retention-sweep`). The row shows when
|
|
617
|
+
the sweep ran and what it changed.
|
|
608
618
|
|
|
609
619
|
`artifacty integrity` gains a check that no orphaned files remain after a
|
|
610
620
|
purge.
|
|
@@ -631,9 +641,9 @@ New columns on `artifacts`:
|
|
|
631
641
|
- `visibility TEXT NOT NULL DEFAULT 'team'` with values `private`, `team`.
|
|
632
642
|
- `owner_user_id TEXT` backfilled from `publisher_user_id` on migration.
|
|
633
643
|
|
|
634
|
-
Optional teams are
|
|
635
|
-
of this server". A later version can add a `groups` table
|
|
636
|
-
the API shape.
|
|
644
|
+
Optional teams are outside the v1 scope. In this design, `team` means "all
|
|
645
|
+
authenticated users of this server". A later version can add a `groups` table
|
|
646
|
+
without changing the API shape.
|
|
637
647
|
|
|
638
648
|
### Rules
|
|
639
649
|
|
|
@@ -657,8 +667,9 @@ the API shape.
|
|
|
657
667
|
|
|
658
668
|
### Browser
|
|
659
669
|
|
|
660
|
-
|
|
661
|
-
|
|
670
|
+
The viewer shows a visibility badge. The edit form gives owners and
|
|
671
|
+
administrators a visibility toggle. The account page lists "My private
|
|
672
|
+
artifacts".
|
|
662
673
|
|
|
663
674
|
### Tests
|
|
664
675
|
|
|
@@ -682,11 +693,11 @@ Scopes:
|
|
|
682
693
|
| `write` | create, import, update, link, comment, archive/restore of own artifacts |
|
|
683
694
|
| `admin` | everything the user role allows; only available to admin users |
|
|
684
695
|
|
|
685
|
-
- `authenticateApiToken` returns `scopes
|
|
686
|
-
helper in `src/lib/security.js
|
|
687
|
-
|
|
688
|
-
`token-scope-denied` audit row
|
|
689
|
-
|
|
696
|
+
- `authenticateApiToken` returns `scopes`. Each HTTP route and MCP tool handler
|
|
697
|
+
calls a new `requireScope(auth, scope)` helper in `src/lib/security.js`.
|
|
698
|
+
A denial returns `403` with `code: "scope_denied"` and writes a
|
|
699
|
+
`token-scope-denied` audit row. Limit these audit rows to one per token per
|
|
700
|
+
minute to prevent excessive logging.
|
|
690
701
|
- MCP `tools/list` filters out mutating tools when the authenticated token
|
|
691
702
|
lacks `write`, so read-only agents never see tools they cannot call.
|
|
692
703
|
- `/account` token creation form adds scope checkboxes; `artifacty token`
|
|
@@ -704,8 +715,8 @@ admin role, default for legacy tokens.
|
|
|
704
715
|
|
|
705
716
|
### Design
|
|
706
717
|
|
|
707
|
-
|
|
708
|
-
|
|
718
|
+
Use a fixed-window counter in memory, keyed by `(principal, bucket)`. Select
|
|
719
|
+
the principal in this order: token id, user id, then remote address.
|
|
709
720
|
|
|
710
721
|
| Bucket | Default limit | Env |
|
|
711
722
|
| --- | --- | --- |
|
|
@@ -731,8 +742,8 @@ header.
|
|
|
731
742
|
|
|
732
743
|
### Problem
|
|
733
744
|
|
|
734
|
-
The current bundle excludes users, sessions, tokens, and audit logs
|
|
735
|
-
server
|
|
745
|
+
The current bundle excludes users, sessions, tokens, and audit logs. Moving
|
|
746
|
+
the store to another server therefore requires manual steps.
|
|
736
747
|
|
|
737
748
|
### Design
|
|
738
749
|
|
|
@@ -762,11 +773,11 @@ sessions absent, file mode.
|
|
|
762
773
|
|
|
763
774
|
### Design
|
|
764
775
|
|
|
765
|
-
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
776
|
+
- Use the bundled CodeMirror language packages in read-only mode to highlight
|
|
777
|
+
fenced code blocks in Markdown artifacts. In the browser, `viewer.js` applies
|
|
778
|
+
highlighting to `<pre><code class="language-x">` elements. The server returns
|
|
779
|
+
plain escaped HTML. Rendering must still work without JavaScript and with
|
|
780
|
+
strict CSP settings.
|
|
770
781
|
- ```` ```mermaid ```` fences render through the existing sandboxed Mermaid
|
|
771
782
|
iframe path, one iframe per diagram, lazily created when scrolled into view.
|
|
772
783
|
A per-document cap (`ARTIFACTY_MAX_INLINE_DIAGRAMS`, default 20) prevents
|
|
@@ -789,14 +800,14 @@ sanitization unchanged for inline HTML in Markdown.
|
|
|
789
800
|
- New format `notebook` (`.ipynb`, `application/x-ipynb+json`), default
|
|
790
801
|
artifact type `analysis-report`.
|
|
791
802
|
- Import detection: JSON object with `nbformat` and `cells[]`.
|
|
792
|
-
-
|
|
793
|
-
|
|
794
|
-
-
|
|
795
|
-
code cells as highlighted source
|
|
796
|
-
`text/markdown`, `image/png`, `image/jpeg`,
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
the type name.
|
|
803
|
+
- The converter produces a normalized structure only for rendering. Store
|
|
804
|
+
the original notebook JSON.
|
|
805
|
+
- The viewer renders cells in order. Render Markdown cells through the
|
|
806
|
+
Markdown pipeline and code cells as highlighted source. Allow these output
|
|
807
|
+
types: `text/plain`, `text/markdown`, `image/png`, `image/jpeg`, and
|
|
808
|
+
`image/svg+xml`. Sanitize SVG output and render it in the scriptless SVG
|
|
809
|
+
iframe. Render `text/html` output in the sandboxed HTML iframe, as for HTML
|
|
810
|
+
artifacts. For other MIME types, show a placeholder with the type name.
|
|
800
811
|
- Size guard: outputs larger than 2 MB are replaced with a "truncated" notice.
|
|
801
812
|
- `artifacty import --agent generic --file notebook.ipynb` and the browser
|
|
802
813
|
import page detect it automatically.
|
|
@@ -820,8 +831,8 @@ createStructuredDiff(before, after, { format })
|
|
|
820
831
|
|
|
821
832
|
| Format | Strategy |
|
|
822
833
|
| --- | --- |
|
|
823
|
-
| `json`, `sarif`, `notebook` |
|
|
824
|
-
| `csv` |
|
|
834
|
+
| `json`, `sarif`, `notebook` | Compare objects recursively. Produce `added`, `removed`, and `changed` entries keyed by JSON path. Match array objects by `id`, `ruleId`, or `path` when available. Otherwise, match by index. |
|
|
835
|
+
| `csv` | Compare rows using their headers. If the first column is unique, match rows by that column. Otherwise, match by position. Report added, removed, and changed cells. |
|
|
825
836
|
| `markdown`, `text`, `code`, `html` | Existing line diff plus word-level highlighting inside changed lines. |
|
|
826
837
|
| `bundle` | Per-file diff using the strategy of each file's format. |
|
|
827
838
|
|
|
@@ -873,10 +884,10 @@ artifacty watch --artifact release-handoff-abc12345 --exec "./on-change.sh"
|
|
|
873
884
|
```
|
|
874
885
|
|
|
875
886
|
- Connects to `/api/events` using the URL from `server.json` or
|
|
876
|
-
`ARTIFACTY_URL
|
|
887
|
+
`ARTIFACTY_URL`. If the connection drops, reconnects with `Last-Event-ID`.
|
|
877
888
|
- Prints one JSON line per event with `--json`, or a human line otherwise.
|
|
878
|
-
- `--exec` runs the command with
|
|
879
|
-
environment variables
|
|
889
|
+
- `--exec` runs the command with event JSON on stdin and `ARTIFACTY_EVENT_*`
|
|
890
|
+
environment variables. It prints failures and continues watching.
|
|
880
891
|
- `--once` exits after the first match (a shell-friendly `artifacty_wait`).
|
|
881
892
|
|
|
882
893
|
### `artifacty diff`
|
|
@@ -904,8 +915,9 @@ code, `--exec` environment injection.
|
|
|
904
915
|
### Design
|
|
905
916
|
|
|
906
917
|
- `src/lib/openapi.js` builds an OpenAPI 3.1 document from a single route
|
|
907
|
-
table
|
|
908
|
-
|
|
918
|
+
table. `server.js` uses the same table to dispatch requests. This keeps the
|
|
919
|
+
specification consistent with the implementation. Each route entry has this
|
|
920
|
+
shape:
|
|
909
921
|
|
|
910
922
|
```js
|
|
911
923
|
{ method: "POST", path: "/api/artifacts", handler, auth: "write", summary, requestSchema, responseSchema }
|
|
@@ -926,16 +938,16 @@ code, `--exec` environment injection.
|
|
|
926
938
|
|
|
927
939
|
### Design
|
|
928
940
|
|
|
929
|
-
-
|
|
930
|
-
|
|
941
|
+
- Before implementing sections 3 and 5, check the custom implementation
|
|
942
|
+
against the newest MCP specification. Use this checklist:
|
|
931
943
|
- Negotiate the newest protocol version while continuing to accept
|
|
932
944
|
`2025-06-18` from older clients.
|
|
933
945
|
- `tools/list` `outputSchema` for every tool that returns
|
|
934
946
|
`structuredContent`, generated from the same schema table as section 19.
|
|
935
947
|
- `resources/subscribe`, `listChanged` notifications (section 3).
|
|
936
|
-
- Elicitation: if the client advertises `elicitation`,
|
|
937
|
-
without `expectedVersion`
|
|
938
|
-
|
|
948
|
+
- Elicitation: if a conflict occurs and the client advertises `elicitation`,
|
|
949
|
+
`artifacty_update` without `expectedVersion` may ask the user whether to
|
|
950
|
+
rebase. Otherwise, return the conflict error.
|
|
939
951
|
- Pagination cursors on `tools/list`, `resources/list`, and
|
|
940
952
|
`prompts/list` when result counts exceed 50.
|
|
941
953
|
- Streamable HTTP session resumption on `/mcp` (`Mcp-Session-Id`, event
|
|
@@ -961,10 +973,10 @@ subscribe flow, cursor pagination, session resume through the HTTP transport.
|
|
|
961
973
|
| 4 | 5 Comments, 8 Filters and views, 9 Retention | 8 | Day-to-day usability and long-running store health. |
|
|
962
974
|
| 5 | 6 Semantic search, 14 Markdown rendering, 15 Notebook, 7 SARIF/CSV, 17 Document assets | 8 (no bump; new tables are created idempotently) | Content and discovery improvements that build on everything above. |
|
|
963
975
|
|
|
964
|
-
|
|
965
|
-
`docs/mcp-public-api.md`, `docs/threat-model.md`, and `docs/artifact-schema-v1.md
|
|
966
|
-
|
|
967
|
-
`STORE_VERSION`
|
|
976
|
+
At the end of each phase, run `npm run release:check`. Update `README.md`,
|
|
977
|
+
`docs/mcp-public-api.md`, `docs/threat-model.md`, and `docs/artifact-schema-v1.md`.
|
|
978
|
+
If the artifact envelope changes, use a `v2` schema document. Increase
|
|
979
|
+
`STORE_VERSION` only if the phase added a table or column.
|
|
968
980
|
|
|
969
981
|
### Compatibility guarantees across all phases
|
|
970
982
|
|
|
@@ -1,38 +1,37 @@
|
|
|
1
1
|
# SARIF and CSV Artifact Support
|
|
2
2
|
|
|
3
|
-
Artifacty supports SARIF and CSV as **output artifacts
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Artifacty supports SARIF and CSV as **output artifacts**. Codex and other agents
|
|
4
|
+
can share these artifacts for review. This scope excludes Codex input context,
|
|
5
|
+
appshots, thread state, and client-specific UI state.
|
|
6
6
|
|
|
7
7
|
## Implemented Behavior
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
|
|
9
|
+
- HTTP, CLI, MCP, storage, and browser forms support `sarif` and `csv` as
|
|
10
|
+
`format` values.
|
|
11
11
|
- `.sarif`, `.sarif.json`, `application/sarif+json`, `.csv`, and `text/csv`
|
|
12
|
-
inputs are detected
|
|
13
|
-
- SARIF top-level objects with `version` and `runs[]`
|
|
12
|
+
inputs are detected by the importer.
|
|
13
|
+
- The importer stores SARIF top-level objects with `version` and `runs[]` as
|
|
14
14
|
`analysis-report` artifacts.
|
|
15
|
-
- CSV inputs default to `table
|
|
16
|
-
findings
|
|
15
|
+
- CSV inputs default to `table`. If a CSV file appears to contain security
|
|
16
|
+
or review findings, the importer selects `analysis-report`.
|
|
17
17
|
- `/raw` always returns the original stored source, unaffected by rendering,
|
|
18
18
|
sort/filter, or export.
|
|
19
19
|
|
|
20
20
|
## Browser Rendering
|
|
21
21
|
|
|
22
|
-
- SARIF
|
|
23
|
-
and note counts.
|
|
22
|
+
- The SARIF viewer limits the findings summary size. The summary includes run,
|
|
23
|
+
result, error, warning, and note counts.
|
|
24
24
|
- SARIF result rows show level, rule id, message, first location, and tool name.
|
|
25
25
|
- The full formatted SARIF JSON remains available in a details panel.
|
|
26
26
|
- CSV renders as an escaped table with bounded rows and columns.
|
|
27
|
-
-
|
|
28
|
-
JSON
|
|
27
|
+
- If CSV is malformed or JSON is not SARIF, the viewer displays escaped source
|
|
28
|
+
or formatted JSON. It does not render an unsafe table.
|
|
29
29
|
|
|
30
30
|
## Sort, Filter, and Download (roadmap section 7)
|
|
31
31
|
|
|
32
|
-
- The
|
|
33
|
-
`src/client/viewer.js
|
|
34
|
-
|
|
35
|
-
disabled.
|
|
32
|
+
- The server renders a limited set of SARIF results or CSV rows.
|
|
33
|
+
`src/client/viewer.js` adds controls to that data in the browser. The server
|
|
34
|
+
output remains correct and readable when JavaScript is disabled.
|
|
36
35
|
- SARIF: level filter chips (`error`, `warning`, `note`), a rule id text
|
|
37
36
|
filter, and click-to-sort on the Level/Rule/Location columns, plus a
|
|
38
37
|
visible result count.
|
|
@@ -47,17 +46,17 @@ context, appshots, thread state, and client-specific UI state.
|
|
|
47
46
|
comma-separated subset of `error`, `warning`, `note`, `none`; `rule` is a
|
|
48
47
|
case-insensitive rule id substring match. The exported document keeps
|
|
49
48
|
only the matching results per run and stays structurally valid SARIF.
|
|
50
|
-
- The route
|
|
51
|
-
streams the result with `Content-Disposition: attachment` and
|
|
52
|
-
matching content type
|
|
53
|
-
size
|
|
54
|
-
would
|
|
49
|
+
- The route parses the original stored content again. It does not read
|
|
50
|
+
`/raw`. It streams the result with `Content-Disposition: attachment` and
|
|
51
|
+
the matching content type. The export cannot exceed the store's maximum
|
|
52
|
+
artifact byte size. The route removes trailing rows or results in a fixed
|
|
53
|
+
order when they would exceed that limit.
|
|
55
54
|
- Invalid parameters (unknown format, unknown sort/filter column, bad
|
|
56
55
|
`dir`, unknown SARIF level, or an artifact whose stored format doesn't
|
|
57
56
|
match `format`) return HTTP 400 with `code: "invalid_export"`.
|
|
58
|
-
- Shared filter
|
|
59
|
-
`src/lib/sarif-csv-export.js
|
|
60
|
-
|
|
57
|
+
- Shared filter, sort, and serialization functions are in
|
|
58
|
+
`src/lib/sarif-csv-export.js`. They are separate from the display parsing
|
|
59
|
+
functions in `src/lib/render.js`.
|
|
61
60
|
|
|
62
61
|
## Verification Coverage
|
|
63
62
|
|
|
@@ -76,4 +75,4 @@ context, appshots, thread state, and client-specific UI state.
|
|
|
76
75
|
|
|
77
76
|
## Future Extensions
|
|
78
77
|
|
|
79
|
-
-
|
|
78
|
+
- No extensions are currently planned. See roadmap-design.md for the full roadmap.
|