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/CLAUDE.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This file provides guidance to Claude Code when working with this repository.
|
|
4
4
|
|
|
5
|
-
Artifacty is a local, agent-to-agent artifact exchange for LLM workflows. One agent publishes an artifact
|
|
5
|
+
Artifacty is a local, agent-to-agent artifact exchange for LLM workflows. One agent publishes an artifact. Other agents can list, read, import, update, and continue from it without copying content through chat. HTTP, the browser, the CLI, and MCP stdio use the same store.
|
|
6
6
|
|
|
7
7
|
See `AGENTS.md` for repository structure, coding-style conventions, and commit/PR guidelines.
|
|
8
8
|
|
|
9
|
+
For English and Korean documentation, follow the [writing style guide](docs/writing-style.md). Use clear sentences and consistent terms. Keep technical vocabulary precise. Write Korean in natural, fluent Korean rather than translating English sentence patterns.
|
|
10
|
+
|
|
9
11
|
## Commands
|
|
10
12
|
|
|
11
13
|
- `npm test` — run all tests with `node --test`.
|
|
@@ -16,7 +18,7 @@ See `AGENTS.md` for repository structure, coding-style conventions, and commit/P
|
|
|
16
18
|
- `node src/mcp-server.js` or `npm run mcp` — run the MCP stdio server.
|
|
17
19
|
- `node src/cli.js help` — inspect CLI usage.
|
|
18
20
|
|
|
19
|
-
Run `npm run release:check` before claiming a release-ready change. There is no build step; this is plain ESM run directly by Node `>=22.
|
|
21
|
+
Run `npm run release:check` before claiming a release-ready change. There is no build step; this is plain ESM run directly by Node `>=22.12.0`.
|
|
20
22
|
|
|
21
23
|
## Architecture
|
|
22
24
|
|
|
@@ -39,7 +41,9 @@ The store lives at `ARTIFACTY_HOME` or `~/.artifacty` by default.
|
|
|
39
41
|
- `server.json` records the currently running browser server URL so CLI and MCP responses keep working when the default port falls back.
|
|
40
42
|
- Legacy `index.json` stores migrate automatically on first access.
|
|
41
43
|
|
|
42
|
-
Versions are append-only.
|
|
44
|
+
Versions are append-only. To correct a historical version, use the admin repair (`replaceArtifactVersion`) or delete (`deleteArtifactVersion`) path. These paths record every change in the audit log. Do not modify prior content files through other paths.
|
|
45
|
+
|
|
46
|
+
Before changing upgrade behavior, read [upgrade snapshots and recovery](docs/upgrade-backups.md). `src/lib/upgrade-backup.js` protects schema migrations with a mandatory verified snapshot. Optional application-update snapshots use `ARTIFACTY_BACKUP_ON_UPDATE=true`. Keep recovery commands independent of normal storage initialization so they cannot trigger migration. Stop every server and MCP process before restoring a store. Test recovery only with temporary stores.
|
|
43
47
|
|
|
44
48
|
### Security Model
|
|
45
49
|
|
|
@@ -51,7 +55,9 @@ Versions are append-only. Do not mutate prior content files, except through the
|
|
|
51
55
|
|
|
52
56
|
### Browser Editor
|
|
53
57
|
|
|
54
|
-
The create/import/edit screens use CodeMirror 6 for Markdown, HTML, JSON, and text editing. CodeMirror assets are served locally through allowlisted `/vendor/npm/*` routes, not from a CDN. UI text defaults to English and supports Korean with `?lang=ko
|
|
58
|
+
The create/import/edit screens use CodeMirror 6 for Markdown, HTML, JSON, and text editing. CodeMirror assets are served locally through allowlisted `/vendor/npm/*` routes, not from a CDN. UI text defaults to English and supports Korean with `?lang=ko`. Keep each document in its existing language unless a translation is requested.
|
|
59
|
+
|
|
60
|
+
Mermaid uses version 12.1.0 with the existing `classic` look, `dagre` layout, and `default` theme. Its browser code requires ES2024 support, such as Safari 17.4 or newer. The optional Babel 8 React renderer requires Node `^22.18.0 || >=24.11.0`.
|
|
55
61
|
|
|
56
62
|
### MCP Server
|
|
57
63
|
|
package/README.md
CHANGED
|
@@ -3,19 +3,24 @@
|
|
|
3
3
|
[](https://github.com/raeseoklee/artifacty/actions/workflows/publish.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/artifacty)
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[](package.json)
|
|
7
7
|
|
|
8
|
-
Artifacty
|
|
8
|
+
Artifacty gives AI-generated artifacts a local home that agents can share. Claude, Codex, Gemini, GitHub Copilot, Cursor, and other MCP tools can publish artifacts to the same store. Other agents can find, read, and update them without copying content through chat.
|
|
9
9
|
|
|
10
10
|

|
|
11
11
|
|
|
12
12
|
## Why MCP
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Artifacts turn session output into shareable, versioned pages. Artifacty keeps those pages local and makes them available across agents. The browser server renders artifacts for people. The MCP stdio server gives agents a common tool interface.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
|
-
Artifacty requires Node.js 22.
|
|
18
|
+
Artifacty requires Node.js 22.12.0 or newer.
|
|
19
|
+
|
|
20
|
+
The optional React renderer uses Babel 8. Its supported Node.js versions are
|
|
21
|
+
`^22.18.0 || >=24.11.0`. Use a compatible version if you enable that renderer.
|
|
22
|
+
|
|
23
|
+
The browser renderer uses Mermaid 12.1.0. Use a current browser with ES2024 support, such as Safari 17.4 or newer. Mermaid keeps the `classic` look, `dagre` layout, and `default` theme.
|
|
19
24
|
|
|
20
25
|
Install the CLI globally from npm:
|
|
21
26
|
|
|
@@ -36,7 +41,7 @@ Start the local dashboard in the background:
|
|
|
36
41
|
artifacty serve
|
|
37
42
|
```
|
|
38
43
|
|
|
39
|
-
Open the `url`
|
|
44
|
+
Open the `url` in the JSON response. Artifacty prefers `http://127.0.0.1:8787`. If that port is busy and you did not configure a port, Artifacty uses the next available local port. It records the actual URL for CLI and MCP responses.
|
|
40
45
|
|
|
41
46
|
Manage the background server:
|
|
42
47
|
|
|
@@ -45,8 +50,8 @@ artifacty status
|
|
|
45
50
|
artifacty stop
|
|
46
51
|
```
|
|
47
52
|
|
|
48
|
-
`artifacty start` and `artifacty serve --detach` use the same lifecycle path as `artifacty serve`.
|
|
49
|
-
These
|
|
53
|
+
`artifacty start` and `artifacty serve --detach` use the same lifecycle path as `artifacty serve`. Artifacty writes logs under `~/.artifacty/logs/`.
|
|
54
|
+
These commands use Node's detached process support on macOS, Linux, and Windows. `artifacty stop` uses process-group signals on macOS and Linux. On Windows, it uses `taskkill`. If Windows requires forceful termination, it retries with `/F`.
|
|
50
55
|
|
|
51
56
|
For foreground debugging, keep the process attached:
|
|
52
57
|
|
|
@@ -174,7 +179,7 @@ them as HTML instead of plain text.
|
|
|
174
179
|
|
|
175
180
|
## Agent Handoff Example
|
|
176
181
|
|
|
177
|
-
One agent
|
|
182
|
+
One agent publishes a handoff artifact. Another agent finds it, reads the context, and appends the next version.
|
|
178
183
|
|
|
179
184
|
Codex publishes the handoff:
|
|
180
185
|
|
|
@@ -259,7 +264,9 @@ By default Artifacty stores files under `~/.artifacty`.
|
|
|
259
264
|
ARTIFACTY_HOME=/path/to/shared/store artifacty serve
|
|
260
265
|
```
|
|
261
266
|
|
|
262
|
-
|
|
267
|
+
Artifacty stores metadata in `artifacty.sqlite`. Normal create and update operations append version files under `artifacts/`. Administrators can repair or delete individual versions from the browser. The audit log records these exceptions.
|
|
268
|
+
|
|
269
|
+
Artifacty writes the current browser server URL to `server.json`. MCP tools use this URL to return correct links when the server selects another port. On first access, Artifacty automatically migrates existing `index.json` stores.
|
|
263
270
|
|
|
264
271
|
Every artifact row carries a `visibility` (`private`/`team`, default `team`) and an `ownerUserId`, backfilled from the artifact's `publisherUserId` on migration. See the Security Model section below for the access rules these enforce.
|
|
265
272
|
|
|
@@ -286,13 +293,23 @@ as artifacts-only. For large migrations or scripted server moves, use
|
|
|
286
293
|
`artifacty backup --full` and
|
|
287
294
|
`artifacty import-store --file ./artifacty-backup.json --confirm replace-all`.
|
|
288
295
|
|
|
289
|
-
|
|
296
|
+
If the local Node SQLite build supports FTS5, search uses a SQLite FTS5 index. It covers the latest version body, title, tags, source agent, artifact type, format, and metadata summary. If FTS5 is unavailable, Artifacty uses metadata search. To rebuild or check the store, run:
|
|
290
297
|
|
|
291
298
|
```bash
|
|
292
299
|
artifacty index rebuild
|
|
293
300
|
artifacty integrity
|
|
294
301
|
```
|
|
295
302
|
|
|
303
|
+
### Upgrade Snapshots
|
|
304
|
+
|
|
305
|
+
Before an existing store needs a schema migration, Artifacty creates and verifies a mandatory local snapshot. The snapshot includes the raw SQLite database, referenced version files, and legacy index. If snapshot verification fails, migration stops.
|
|
306
|
+
|
|
307
|
+
Set `ARTIFACTY_BACKUP_ON_UPDATE=true` to also snapshot application-version changes. If an existing store has no recorded application version, its first open with this setting creates a baseline snapshot. `ARTIFACTY_UPGRADE_BACKUP_KEEP` retains the latest three automatic snapshots by default (valid range: 1–1000).
|
|
308
|
+
|
|
309
|
+
Use `artifacty backups list`, `artifacty backups verify <id>`, and `artifacty backups restore <id> --confirm restore-store`. Stop every server and MCP process before an upgrade or restore. Restore creates a recovery snapshot before replacing the store. It also restores credentials and security state; previously revoked sessions, tokens, and links can become valid again.
|
|
310
|
+
|
|
311
|
+
These local snapshots are separate from portable `artifacty backup`/`export` JSON bundles. See [upgrade snapshots and recovery](docs/upgrade-backups.md) for verification, corrupt-store recovery, and interrupted-restore procedures.
|
|
312
|
+
|
|
296
313
|
### Semantic Search
|
|
297
314
|
|
|
298
315
|
`?mode=keyword|semantic|hybrid` on `GET /api/artifacts`, the dashboard, `artifacty list --mode`, and the MCP `artifacty_list` tool add optional natural-language search on top of FTS5, without any bundled model or mandatory dependency:
|
|
@@ -314,7 +331,7 @@ export ARTIFACTY_EMBEDDINGS_API_KEY=sk-...
|
|
|
314
331
|
export ARTIFACTY_EMBEDDINGS_COMMAND="python3 embed.py"
|
|
315
332
|
```
|
|
316
333
|
|
|
317
|
-
|
|
334
|
+
Artifacty reads the API key only from the environment. It does not log the key, return it in errors, or save it to the store. `artifacty doctor` reports the provider and model with the key redacted. After a create or update, Artifacty generates embeddings in the background. To generate or refresh embeddings for existing artifacts in batches of 16, run:
|
|
318
335
|
|
|
319
336
|
```bash
|
|
320
337
|
artifacty index rebuild --embeddings
|
|
@@ -322,7 +339,7 @@ artifacty index rebuild --embeddings
|
|
|
322
339
|
|
|
323
340
|
### Relations
|
|
324
341
|
|
|
325
|
-
|
|
342
|
+
Use typed, directional relations to connect a handoff, its review, and follow-up work:
|
|
326
343
|
|
|
327
344
|
- Relation names are a closed set for v1: `derived-from`, `supersedes`, `reviews`, `references`, `part-of`.
|
|
328
345
|
- Every relation has a computed inverse (`derived-from` ↔ `derives`, `supersedes` ↔ `superseded-by`, `reviews` ↔ `reviewed-by`, `references` ↔ `referenced-by`, `part-of` ↔ `contains`) shown automatically on the other side.
|
|
@@ -339,12 +356,12 @@ artifacty unlink <from-id> derived-from <to-id>
|
|
|
339
356
|
|
|
340
357
|
### Comments and review status
|
|
341
358
|
|
|
342
|
-
|
|
359
|
+
Add feedback to a specific version without publishing a new version or a separate review artifact:
|
|
343
360
|
|
|
344
|
-
- Comments
|
|
361
|
+
- Comments use the same sanitized Markdown renderer as artifact content. Each comment has a 16 KB limit. The optional `anchor` field provides a display hint: `{ line: 42 }` for text, `{ path: "$.runs[0].results[3]" }` for JSON/SARIF, or `{ row: 7 }` for CSV. Artifacty does not validate the hint against the content.
|
|
345
362
|
- Threads are one level deep: `parentId` on a new comment must point to a root comment (one with no `parentId` of its own).
|
|
346
363
|
- Deleting a comment is a soft delete: it disappears from `artifacty comments`/`GET .../comments` but its audit-log entry is kept. Pass `--include-deleted`/`includeDeleted=true` to see it anyway.
|
|
347
|
-
-
|
|
364
|
+
- Each artifact has a `reviewStatus`: `none`, `pending`, `changes-requested`, or `approved`. Set the status explicitly. If you append a version to an approved artifact, Artifacty resets the status to `pending`. The update's audit metadata records this change.
|
|
348
365
|
- `GET`/`POST /api/artifacts/:id/comments`, `POST /api/artifacts/:id/comments/:commentId/resolve`, `DELETE /api/artifacts/:id/comments/:commentId`, and `POST /api/artifacts/:id/review-status` manage comments and review status over HTTP.
|
|
349
366
|
- `artifacty_comment`, `artifacty_resolve_comment`, and `artifacty_set_review_status` are the MCP equivalents; `artifacty_get` accepts `includeComments: true` to return the requested version's open comments alongside the artifact.
|
|
350
367
|
- The browser artifact page shows a comments panel grouped by version, with a reply form, a resolve button, and (for the artifact's owner or an admin) a review-status selector. Line-anchored comments are shown as plain text (e.g. "line 42") rather than a CodeMirror gutter marker.
|
|
@@ -358,7 +375,9 @@ artifacty review-status release-handoff-abc12345 approved
|
|
|
358
375
|
|
|
359
376
|
### Diff
|
|
360
377
|
|
|
361
|
-
`artifacty diff <id> [--from N] [--to M] [--structured] [--json]` compares two versions
|
|
378
|
+
`artifacty diff <id> [--from N] [--to M] [--structured] [--json]` compares two artifact versions. By default, `--to` selects the latest version and `--from` selects `--to - 1`.
|
|
379
|
+
|
|
380
|
+
JSON, SARIF, CSV, notebook, and bundle artifacts use a structured diff by default. The output contains JSON paths, CSV rows and cells, or bundle files. Other formats use a line diff. To request a structured diff for any format, use `--structured`; text lines include word highlights. To print machine-readable output instead of unified text, use `--json`.
|
|
362
381
|
|
|
363
382
|
```bash
|
|
364
383
|
artifacty diff release-handoff-abc12345
|
|
@@ -367,14 +386,16 @@ artifacty diff release-handoff-abc12345 --from 1 --to 3 --json
|
|
|
367
386
|
|
|
368
387
|
### Retention
|
|
369
388
|
|
|
370
|
-
|
|
389
|
+
By default, Artifacty does not limit retained artifacts, audit rows, or events. Administrators can set a retention policy at `/admin/retention` or with `artifacty retention set`. Artifacty stores the policy in the `meta` table:
|
|
371
390
|
|
|
372
391
|
- `archiveAfterDays` (a default plus optional per-artifact-type overrides) auto-archives artifacts that have not been updated within the window, unless the artifact carries a tag in `keepTags` or has `reviewStatus: "approved"`.
|
|
373
392
|
- `purgeArchivedAfterDays` hard-deletes artifacts that have been archived longer than the window, including their version files, dependent rows that cascade via foreign keys (comments, relations, embeddings), and their `events`/search-index rows. Audit log rows for the artifact are deliberately kept (see `auditRetentionDays` below) as the historical record that the purge happened, even though the artifact itself is gone. This is the only retention action that deletes data outright, so it is refused unless the operator has set `ARTIFACTY_RETENTION_ALLOW_PURGE=true` in the server environment; `--allow-purge` (or the `allowPurge` request field) only opts a single run in and never sets that environment variable itself. Always dry-run first (`artifacty retention run --dry-run`, or the report on `/admin/retention`) to review what would be purged.
|
|
374
393
|
- `auditRetentionDays` prunes old audit log rows, except `version-repair`, `version-delete`, `retention-purge`, `retention-policy-update`, and `owner-change`, which are kept indefinitely.
|
|
375
394
|
- `eventRetentionRows` caps how many rows the `events` change-notification table keeps.
|
|
376
395
|
|
|
377
|
-
|
|
396
|
+
The HTTP server runs a background sweep every `ARTIFACTY_RETENTION_INTERVAL_MS` (default one hour). Each sweep checks the current policy. The timer starts even if no policy is set. A later policy change takes effect on the next sweep without a restart.
|
|
397
|
+
|
|
398
|
+
If a purge is interrupted, `artifacty integrity`/`checkStoreIntegrity` reports files left behind. `artifacty doctor` reports the current retention policy summary.
|
|
378
399
|
|
|
379
400
|
```bash
|
|
380
401
|
artifacty retention show
|
|
@@ -439,7 +460,9 @@ curl -s -X POST http://127.0.0.1:8787/api/webhooks \
|
|
|
439
460
|
-d '{ "url": "https://example.com/hooks/artifacty", "eventTypes": ["artifact.updated"] }'
|
|
440
461
|
```
|
|
441
462
|
|
|
442
|
-
|
|
463
|
+
Save `secret` from the response. Artifacty returns it only once. Each delivery sends JSON with `POST` and these headers: `X-Artifacty-Event`, `X-Artifacty-Delivery`, and `X-Artifacty-Signature: sha256=<hmac>`. Failed deliveries retry up to three times, after 2, 10, and 60 seconds. After 20 consecutive failures, Artifacty disables the webhook.
|
|
464
|
+
|
|
465
|
+
Manage webhooks at `/admin/webhooks` in the browser. The API provides `GET/POST /api/webhooks`, `DELETE /api/webhooks/:id`, and `POST /api/webhooks/:id/test`. See [docs/threat-model.md](docs/threat-model.md) for the signature scheme and SSRF guard.
|
|
443
466
|
|
|
444
467
|
**MCP:** `resources/subscribe` on `artifacty://artifacts/{id}` or `artifacty://recent` delivers `notifications/resources/updated` over the stdio transport. The `artifacty_wait` tool (`{ artifactId?, tag?, type?, timeoutMs }`, max 120000ms) is a long-poll alternative that works over any transport, including the stateless `/mcp` HTTP transport where `resources/subscribe` cannot push notifications. See [docs/mcp-public-api.md](docs/mcp-public-api.md).
|
|
445
468
|
|
|
@@ -519,11 +542,13 @@ If the artifact's `latestVersion` no longer matches, the update is rejected with
|
|
|
519
542
|
{ "error": "Version conflict", "code": "version_conflict", "details": { "latestVersion": 4 } }
|
|
520
543
|
```
|
|
521
544
|
|
|
522
|
-
`GET /api/artifacts/:id` sets an `ETag` header
|
|
545
|
+
`GET /api/artifacts/:id` sets an `ETag` header. If the request's `If-None-Match` matches the current version, the server returns `304 Not Modified`. The optional `expectedVersion` field preserves compatibility with clients that omit it.
|
|
546
|
+
|
|
547
|
+
The browser editor sends a hidden `expectedVersion` field. If another agent updated the artifact first, the editor shows a conflict banner with a link to the diff view.
|
|
523
548
|
|
|
524
549
|
## Interface Language
|
|
525
550
|
|
|
526
|
-
The browser UI defaults to English. Add `?lang=ko` to any browser route to use Korean, for example `http://127.0.0.1:8787/new?lang=ko`. Forms and in-app links preserve the selected language.
|
|
551
|
+
The browser UI defaults to English. Add `?lang=ko` to any browser route to use Korean, for example `http://127.0.0.1:8787/new?lang=ko`. Forms and in-app links preserve the selected language. The current product guides are in English. English and Korean documentation follow the [documentation writing guide](docs/writing-style.md). Korean prose should use natural Korean phrasing.
|
|
527
552
|
|
|
528
553
|
Schema and storage:
|
|
529
554
|
|
|
@@ -541,14 +566,127 @@ Schema and storage:
|
|
|
541
566
|
- See [docs/sarif-csv-artifact-plan.md](docs/sarif-csv-artifact-plan.md) for the SARIF/CSV output artifact roadmap.
|
|
542
567
|
- See [docs/roadmap-design.md](docs/roadmap-design.md) for the design of planned features such as relations, change notifications, optimistic concurrency, comments, semantic search, visibility, token scopes, and retention.
|
|
543
568
|
|
|
569
|
+
## Public and Private Access Modes
|
|
570
|
+
|
|
571
|
+
This feature upgrades the SQLite store to version 10. Older builds reject the
|
|
572
|
+
upgraded store rather than ignoring its access policy.
|
|
573
|
+
|
|
574
|
+
Administrators can open **Account → Access** (`/admin/access`) to change the
|
|
575
|
+
server's access mode without restarting it. Existing installations default to
|
|
576
|
+
**public** mode, preserving anonymous dashboard access to team-visible artifacts;
|
|
577
|
+
artifacts marked private remain restricted to their owner and administrators.
|
|
578
|
+
API authentication and write protection still apply in public mode.
|
|
579
|
+
|
|
580
|
+
In **private** mode, browser visitors must sign in. An artifact is readable only
|
|
581
|
+
by its owner, an administrator, or users explicitly granted access, directly or
|
|
582
|
+
through a team. The existing `team` visibility value does not grant all users
|
|
583
|
+
access in this mode. Sharing grants support **read**, **comment**, and **edit**.
|
|
584
|
+
Commenters can add feedback and resolve their own comments; editors can also
|
|
585
|
+
append versions. The strongest direct or team grant applies. Ownership, sharing,
|
|
586
|
+
archiving, and review-status control remain with owners and administrators.
|
|
587
|
+
Administrators can access existing unowned artifacts. They can assign ownership
|
|
588
|
+
or share those artifacts.
|
|
589
|
+
|
|
590
|
+
Create teams on `/admin/access`. Select the members for each team.
|
|
591
|
+
|
|
592
|
+
To grant artifact access:
|
|
593
|
+
|
|
594
|
+
1. Open the artifact as its owner or an administrator.
|
|
595
|
+
2. Open **Sharing**.
|
|
596
|
+
3. Select the allowed users and teams.
|
|
597
|
+
4. Select their permission levels.
|
|
598
|
+
5. Save the sharing settings.
|
|
599
|
+
|
|
600
|
+
The **Effective access** report shows each
|
|
601
|
+
user's actual permission and why it applies, anonymous access, and the global IP
|
|
602
|
+
condition. Removing a grant or team membership takes effect on subsequent reads,
|
|
603
|
+
search results, and change notifications. Personal API tokens carry the same
|
|
604
|
+
user permissions through HTTP and MCP. Shared server tokens have no user
|
|
605
|
+
identity and cannot read or create artifacts through ordinary artifact routes in
|
|
606
|
+
private mode. Trusted local CLI/store access remains an administrative
|
|
607
|
+
filesystem capability.
|
|
608
|
+
|
|
609
|
+
The same admin page accepts an optional IP/CIDR allowlist, one address or network
|
|
610
|
+
per line (for example `192.168.10.0/24` or `2001:db8:1234::/48`). If the list is empty,
|
|
611
|
+
all source addresses are allowed. If the list has entries, it restricts **all HTTP routes**
|
|
612
|
+
in both modes. This includes login, raw downloads, API routes, and HTTP MCP.
|
|
613
|
+
IP permission does not replace user or artifact permissions. Saving a list that
|
|
614
|
+
excludes the administrator's current connection address is rejected. Browser
|
|
615
|
+
changes are provisional for **120 seconds**: confirm that access still works to
|
|
616
|
+
keep the change, or roll it back. Unconfirmed changes revert before the next
|
|
617
|
+
policy check after the deadline, even across server restarts. A second change is
|
|
618
|
+
blocked while confirmation is pending. Mode changes offer a preview of how many
|
|
619
|
+
artifacts will become anonymously readable before you apply them.
|
|
620
|
+
|
|
621
|
+
Address checks use the actual TCP peer, including IPv4-mapped IPv6 addresses;
|
|
622
|
+
`X-Forwarded-For` and `Forwarded` are not trusted. Behind a reverse proxy, the
|
|
623
|
+
peer is the proxy: enforce end-user IP restrictions at that proxy. Local stdio
|
|
624
|
+
MCP and CLI operations do not have an HTTP source IP and are not covered by the
|
|
625
|
+
network allowlist.
|
|
626
|
+
|
|
627
|
+
Full backups include modes, network settings, teams, memberships, sharing grants,
|
|
628
|
+
and inbox entries. Pending network confirmation state and share-link tokens are
|
|
629
|
+
not exported. Artifact-only restores do not restore grants. If they replace existing grants,
|
|
630
|
+
they require confirmation. Restoring a full backup into a private server
|
|
631
|
+
keeps it private even if the backup was public, and an existing network policy
|
|
632
|
+
is preserved.
|
|
633
|
+
|
|
634
|
+
If you switch back to public mode, anonymous visitors can read team-visible
|
|
635
|
+
artifacts again. Artifacty retains explicit sharing grants for a later return
|
|
636
|
+
to private mode.
|
|
637
|
+
|
|
638
|
+
## Share Links and Inbox
|
|
639
|
+
|
|
640
|
+
Owners and administrators can create a read-only link from an artifact's
|
|
641
|
+
**Sharing** page:
|
|
642
|
+
|
|
643
|
+
1. Choose the latest version or pin a particular version.
|
|
644
|
+
2. Set an expiration (seven days by default).
|
|
645
|
+
3. Copy the URL when it is first shown.
|
|
646
|
+
|
|
647
|
+
Only a hash is stored, so the complete URL is not shown again. Links can be
|
|
648
|
+
revoked individually and are permanently revoked on ownership transfer.
|
|
649
|
+
Archived artifacts and deleted versions cannot be read through their links.
|
|
650
|
+
|
|
651
|
+
Links grant access to the selected artifact without an account, so private mode
|
|
652
|
+
requires an administrator to enable **Allow share links in private mode** at
|
|
653
|
+
`/admin/access`. Disabling this policy also disables existing links while the
|
|
654
|
+
server is private. Every link request still obeys the network allowlist. Links
|
|
655
|
+
do not expose the dashboard, history, comments, or editing controls. Public HTML
|
|
656
|
+
previews are static: scripts and external resources are disabled. React,
|
|
657
|
+
Mermaid, SVG and notebook shares show source instead of running active content.
|
|
658
|
+
|
|
659
|
+
The **Inbox** (`/inbox`) lists newly shared artifacts, comments, review requests,
|
|
660
|
+
and new versions for the signed-in user. Events caused by the same user are
|
|
661
|
+
excluded. Read individual notifications or mark all as read. Revoking artifact
|
|
662
|
+
access also hides its notifications and removes them from unread counts.
|
|
663
|
+
|
|
664
|
+
## Sample Manuals
|
|
665
|
+
|
|
666
|
+
Install four English sample artifacts: **Start here**, **Feature guide**,
|
|
667
|
+
**Architecture**, and **Handoff exercise**. Administrators can use the sample
|
|
668
|
+
controls on `/admin/access`; local CLI users can run:
|
|
669
|
+
|
|
670
|
+
```bash
|
|
671
|
+
artifacty samples install
|
|
672
|
+
artifacty samples remove
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Installation is idempotent within the installing account (or local CLI scope).
|
|
676
|
+
Reinstalling restores archived samples without overwriting edits. Removal
|
|
677
|
+
archives managed samples and preserves their versions; it does not delete other
|
|
678
|
+
artifacts with similar names or tags. In private mode, share the installed
|
|
679
|
+
manuals with the intended users or teams from each artifact's Sharing page.
|
|
680
|
+
|
|
544
681
|
## Security Model
|
|
545
682
|
|
|
546
683
|
- The HTTP server binds to `127.0.0.1` by default.
|
|
547
684
|
- If `ARTIFACTY_API_TOKEN` is set, HTTP API routes require `Authorization: Bearer <token>` or `x-artifacty-token`; scripts should prefer headers over `?token=...` URLs.
|
|
548
685
|
- When users exist, personal API tokens issued from `/account` also authenticate HTTP API and MCP requests. Created artifacts record the token owner's email as `publisherId`, and audit logs record the same identity as `actor`.
|
|
549
686
|
- API token checks use timing-safe digest comparison.
|
|
550
|
-
- Personal API tokens
|
|
551
|
-
|
|
687
|
+
- Personal API tokens support `read`, `write`, and `admin` scopes. The default is `read`+`write`. Select scopes when creating a token at `/account`. Only administrator tokens can receive `admin`. Each `/api/*` route requires the matching token scope. The shared `ARTIFACTY_API_TOKEN` and browser sessions have full scopes.
|
|
688
|
+
If a scope check fails, the server returns `403` with `code: "scope_denied"`. It also writes a rate-limited `token-scope-denied` audit row. For MCP tokens without `write`, `tools/list` omits tools that change data. Calls to those tools return `structuredContent.code: "scope_denied"`.
|
|
689
|
+
- Once any user account exists, every artifact has a `visibility` (`private` or `team`, defaulting to `team`) and an `ownerUserId`. In public access mode, `team` is readable and writable by any authenticated principal (unless `ARTIFACTY_TEAM_WRITE=owner` restricts writes to the owner or an admin). `private` is readable and writable only by its owner or an admin; reads by anyone else 404 instead of 403 so the artifact's existence isn't leaked. Archiving, restoring, and changing visibility or ownership always require the owner or an admin, regardless of visibility. A shared `ARTIFACTY_API_TOKEN` (or any request before the first user account is created) has no personal identity and is treated as an anonymous team principal: it can read and write `team` artifacts but never sees `private` ones. In single-user mode (no user accounts at all) every check is bypassed, matching pre-visibility behavior. Change visibility and ownership with `POST /api/artifacts/:id/visibility` and `POST /api/artifacts/:id/owner`, the `artifacty visibility <id> private|team` CLI command, or the `artifacty_set_visibility` MCP tool.
|
|
552
690
|
- HTTP and MCP-over-HTTP requests are rate limited per `(token or user or remote address, bucket)` in fixed one-minute windows: `write` (mutating routes, default 120/min, `ARTIFACTY_RATE_WRITE_PER_MIN`), `auth` (`/login`, default 10/min per address, `ARTIFACTY_RATE_AUTH_PER_MIN`), and `search` (`GET /api/artifacts?q=`, default 300/min, `ARTIFACTY_RATE_SEARCH_PER_MIN`). Rate limiting is disabled on a loopback bind unless `ARTIFACTY_RATE_LIMIT=always`, and always disabled with `ARTIFACTY_RATE_LIMIT=off`. Exceeding a limit returns `429` with a `Retry-After` header, `code: "rate_limited"`, and a rate-limited `rate-limited` audit row.
|
|
553
691
|
- Binding outside localhost requires both `ARTIFACTY_SHARE_MODE=lan` or `team` and `ARTIFACTY_API_TOKEN`.
|
|
554
692
|
- Non-local sharing is intended for trusted LAN or VPN sessions. Prefer a specific interface IP over `0.0.0.0`, keep React rendering disabled, and see [docs/network-sharing.md](docs/network-sharing.md).
|
|
@@ -574,11 +712,13 @@ See [SECURITY.md](SECURITY.md), [docs/threat-model.md](docs/threat-model.md), an
|
|
|
574
712
|
|
|
575
713
|
## Environment Variables
|
|
576
714
|
|
|
577
|
-
|
|
715
|
+
The table lists every `ARTIFACTY_*` variable that Artifacty reads. `node src/cli.js help` prints the same list.
|
|
578
716
|
|
|
579
717
|
| Variable | Purpose | Default |
|
|
580
718
|
| --- | --- | --- |
|
|
581
719
|
| `ARTIFACTY_HOME` | Storage directory | `~/.artifacty` |
|
|
720
|
+
| `ARTIFACTY_BACKUP_ON_UPDATE` | Snapshot existing stores before application-version changes; schema-migration snapshots are always required | `false` |
|
|
721
|
+
| `ARTIFACTY_UPGRADE_BACKUP_KEEP` | Automatic upgrade snapshots to retain; integer from 1 to 1000 | `3` |
|
|
582
722
|
| `ARTIFACTY_URL` | Public URL override; otherwise CLI/MCP read the last running server URL | — |
|
|
583
723
|
| `ARTIFACTY_HOST` | Bind host for the HTTP server | `127.0.0.1` |
|
|
584
724
|
| `ARTIFACTY_PORT` | Bind port for the HTTP server | `8787` |
|
package/SECURITY.md
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Supported Versions
|
|
4
4
|
|
|
5
|
-
Artifacty is pre-1.0.
|
|
6
|
-
minor release. Upgrade to the latest `artifacty` version before reporting a
|
|
5
|
+
Artifacty is pre-1.0. The project provides security fixes for the latest
|
|
6
|
+
published minor release. Upgrade to the latest `artifacty` version before reporting a
|
|
7
7
|
suspected issue.
|
|
8
8
|
|
|
9
9
|
## Reporting a Vulnerability
|
|
10
10
|
|
|
11
11
|
Use GitHub private vulnerability reporting if it is enabled for this repository.
|
|
12
|
-
If private reporting is unavailable, open a GitHub issue with a
|
|
13
|
-
|
|
12
|
+
If private reporting is unavailable, open a GitHub issue with a brief summary.
|
|
13
|
+
Do not include exploit details, secrets, private artifacts, or sensitive
|
|
14
14
|
network information.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Include the following information:
|
|
17
17
|
|
|
18
18
|
- Artifacty version and install method.
|
|
19
19
|
- Node.js version and operating system.
|
|
@@ -23,27 +23,36 @@ Please include:
|
|
|
23
23
|
|
|
24
24
|
## Security Model
|
|
25
25
|
|
|
26
|
-
Artifacty is local-first. The
|
|
27
|
-
outside loopback
|
|
26
|
+
Artifacty is local-first. The HTTP server binds to `127.0.0.1` by default.
|
|
27
|
+
To bind outside loopback, set `ARTIFACTY_SHARE_MODE=lan|team` and an API token.
|
|
28
28
|
|
|
29
29
|
The project treats artifact content as untrusted:
|
|
30
30
|
|
|
31
31
|
- HTML, SVG, Mermaid, and React rendering use sandboxed frames and scoped CSP.
|
|
32
32
|
- React execution is disabled unless `ARTIFACTY_ENABLE_REACT_RENDERER=true`.
|
|
33
|
-
- Mutating browser routes reject
|
|
33
|
+
- Mutating browser routes reject cross-origin writes. They allow loopback and
|
|
34
|
+
same-origin requests.
|
|
34
35
|
- API token checks use constant-time digest comparison.
|
|
35
|
-
-
|
|
36
|
-
|
|
36
|
+
- Before storage, Artifacty scans content for common API keys and private keys.
|
|
37
|
+
The caller can explicitly allow content that contains these keys.
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
Administrators can select public or private site access. Private mode requires
|
|
40
|
+
a personal account and limits artifact access to owners, administrators, and
|
|
41
|
+
users with direct or team grants. Grants permit reading, commenting, or editing.
|
|
42
|
+
Token scopes further restrict API and MCP actions.
|
|
43
|
+
|
|
44
|
+
Administrators can also restrict HTTP access by IP address or CIDR range.
|
|
45
|
+
Artifacty checks the TCP peer address and does not trust forwarding headers.
|
|
46
|
+
Public share links require explicit administrator opt-in in private mode.
|
|
47
|
+
|
|
48
|
+
Artifacty does not provide TLS termination, remote OAuth, or a hosted sync
|
|
49
|
+
service. Do not expose the server directly to the public internet.
|
|
41
50
|
|
|
42
51
|
## Supply Chain
|
|
43
52
|
|
|
44
|
-
npm releases
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
GitHub Actions publishes npm releases through npm Trusted Publishing OIDC.
|
|
54
|
+
Before publication, the release workflow runs lint, tests, and smoke checks on
|
|
55
|
+
supported Node versions.
|
|
47
56
|
|
|
48
57
|
See [docs/threat-model.md](docs/threat-model.md) and
|
|
49
58
|
[docs/network-sharing.md](docs/network-sharing.md) for operational guidance.
|