Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/composable-shared-storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@caplets/core": minor
caplets: minor
---

Add composable shared storage for self-hosted deployments: select one global provider-shaped filesystem, SQLite, PostgreSQL, or S3-compatible `storage` configuration while composing immutable staged Caplets. The core runtime now exposes async storage assembly, generation/health coordination, Storage-facing dashboard management, and explicit inventory, migration, backup, restore, and cutover operations. Document provider prerequisites and keep AWS S3/Cloudflare R2 live validation separate from deterministic PostgreSQL/MinIO evidence.
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ on:
push:
branches:
- main
workflow_dispatch:
inputs:
live:
description: "Run credentialed AWS S3/R2 validation (requires repository variable CAPLETS_STORAGE_LIVE_ENABLED=true)"
required: false
default: false
type: boolean

permissions:
contents: read
Expand Down Expand Up @@ -40,6 +47,68 @@ jobs:
- name: Run quality gates
run: pnpm verify

storage-provider-matrix:
name: Storage provider matrix (Node ${{ matrix.node-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [22, 24]
steps:
- name: Checkout
uses: actions/checkout@v7
Comment on lines +58 to +59

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Set persist-credentials: false on actions/checkout.

Neither checkout disables credential persistence, so the GITHUB_TOKEN is written to .git/config and remains available to any later step. This is especially relevant for storage-provider-live, which also loads long-lived cloud secrets into the job environment.

🔒️ Proposed hardening
       - name: Checkout
         uses: actions/checkout@v7
+        with:
+          persist-credentials: false

As per static analysis (zizmor artipacked: does not set persist-credentials: false).

Also applies to: 94-95

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 58-59: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 58 - 59, Update both actions/checkout
steps in the CI workflow to set persist-credentials to false, ensuring the
GITHUB_TOKEN is not retained in the checked-out repository for subsequent steps.

Source: Linters/SAST tools


- name: Setup pnpm
uses: pnpm/action-setup@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run deterministic storage provider matrix
run: pnpm storage:test:providers

storage-provider-live:
name: Credentialed live storage providers
if: github.event_name == 'workflow_dispatch' && (inputs.live == true) && vars.CAPLETS_STORAGE_LIVE_ENABLED == 'true'
runs-on: ubuntu-latest
env:
CAPLETS_STORAGE_AWS_BUCKET: ${{ secrets.CAPLETS_STORAGE_AWS_BUCKET }}
CAPLETS_STORAGE_AWS_REGION: ${{ secrets.CAPLETS_STORAGE_AWS_REGION }}
CAPLETS_STORAGE_AWS_ENDPOINT: ${{ secrets.CAPLETS_STORAGE_AWS_ENDPOINT }}
CAPLETS_STORAGE_AWS_ACCESS_KEY_ID: ${{ secrets.CAPLETS_STORAGE_AWS_ACCESS_KEY_ID }}
CAPLETS_STORAGE_AWS_SECRET_ACCESS_KEY: ${{ secrets.CAPLETS_STORAGE_AWS_SECRET_ACCESS_KEY }}
CAPLETS_STORAGE_AWS_SESSION_TOKEN: ${{ secrets.CAPLETS_STORAGE_AWS_SESSION_TOKEN }}
CAPLETS_STORAGE_R2_BUCKET: ${{ secrets.CAPLETS_STORAGE_R2_BUCKET }}
CAPLETS_STORAGE_R2_REGION: ${{ secrets.CAPLETS_STORAGE_R2_REGION }}
CAPLETS_STORAGE_R2_ENDPOINT: ${{ secrets.CAPLETS_STORAGE_R2_ENDPOINT }}
CAPLETS_STORAGE_R2_ACCESS_KEY_ID: ${{ secrets.CAPLETS_STORAGE_R2_ACCESS_KEY_ID }}
CAPLETS_STORAGE_R2_SECRET_ACCESS_KEY: ${{ secrets.CAPLETS_STORAGE_R2_SECRET_ACCESS_KEY }}
CAPLETS_STORAGE_R2_SESSION_TOKEN: ${{ secrets.CAPLETS_STORAGE_R2_SESSION_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Setup pnpm
uses: pnpm/action-setup@v6

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run requested live storage targets
run: pnpm storage:test:providers -- --live=aws,r2

changeset:
name: Changeset
runs-on: ubuntu-latest
Expand Down
30 changes: 27 additions & 3 deletions CONCEPTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ Caplets Lockfiles let `caplets install`, no-argument install restore, and `caple

Caplets Lockfiles are share-safe and integrity-aware. They strip credential-bearing source URLs, prefer project-relative paths where possible, verify recorded content before restore, and fail closed when local-source entries are unavailable or marked non-portable.

### Caplet Source Overlay

An ordered composition of Caplet storage sources within one runtime configuration. The v1 cloud overlay reads the global remote store first, then the global filesystem store, then the project filesystem store; a later same-ID definition becomes active while the earlier source remains recorded as shadow provenance.

Caplet Source Overlay precedence is distinct from Namespace Shadowing Policy: an overlay selects one active definition by source priority, while namespace shadowing keeps colliding local and upstream Caplets separately addressable.

### Namespace Shadowing Policy

A Caplet shadowing policy where a local/upstream ID collision exposes both Caplets under qualified namespace IDs and removes the ambiguous bare ID.
Expand All @@ -74,9 +80,27 @@ The Caplets Daemon is installed and updated through an install-time service cont

### Current Host

The Caplets host that served the active dashboard session and owns the runtime state being administered in that session.
The Caplets administration target that served the active dashboard session and owns the runtime state being administered in that session. It may be one host process or a logical deployment of replicas that share one Writable Authority.

Current Host is session-scoped, not a product-wide singleton. The admin dashboard operates on one Current Host while preserving host-scoped terms for future enumeration and switching.

### Writable Authority

The single storage provider that owns dashboard-managed mutable state for a Current Host. A deployment selects filesystem, SQLite, PostgreSQL, or S3-compatible object storage as its Writable Authority rather than assigning different writable providers to individual state domains.

Immutable Staged Filesystem Sources can compose with any Writable Authority, but they do not become additional writable peers.

### Staged Filesystem Source

An immutable Caplet source supplied with each runtime replica through its image or a mounted path.

A Staged Filesystem Source remains readable alongside authority-managed Caplets, reserves its Caplet IDs against dashboard mutation, and is not synchronized through Project Binding or the Writable Authority.

### Authority Generation

A committed revision of shared Current Host state exposed by a Writable Authority.

Current Host is a session-scoped administration target, not a product-wide singleton. The admin dashboard may initially operate only on the Current Host while preserving host-scoped terms for future multi-host enumeration and switching.
Runtime replicas consume complete Authority Generations, reject conflicting writes based on stale state, and retain the last known-good generation when a later refresh fails.

### Caplets Admin Dashboard

Expand All @@ -94,7 +118,7 @@ Daemon-First Setup points MCP clients at `caplets attach <local-daemon-url>` and

A runtime-owned encrypted string store whose values can be referenced from Caplets config with `$vault:NAME` or `${vault:NAME}`.

Caplets Vault replaces fragile agent-harness environment propagation for secret-like config values. Each runtime owns its own Vault store; local Caplets do not read, mirror, or forward remote or Cloud Vault values.
Caplets Vault replaces fragile agent-harness environment propagation for secret-like config values. Each Current Host owns its Vault state; replicas in one Current Host share that state, while separate local, remote, or Cloud Current Hosts do not read, mirror, or forward each other's Vault values.

### Raw Vault Reveal

Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@ caplets vault access grant GH_TOKEN github --remote
Vault values are not exposed through Code Mode, progressive tools, or native agent APIs. Unset or
ungranted Vault references quarantine only the affected Caplet and appear in `caplets doctor`.

## Self-hosted shared storage

Self-hosted deployments select exactly one global provider-shaped `storage` configuration:
filesystem, local SQLite, PostgreSQL, or S3-compatible storage. Image- or mount-staged Caplets
remain immutable read-only inputs. SQLite is single-host; isolate each PostgreSQL deployment with
a dedicated database/connection and each S3 deployment with a distinct bucket/root path.
AWS S3 and Cloudflare R2 require credentialed live evidence before they should be called validated.

See the [self-hosting storage guide](docs/product/self-hosting.md) for provider-shaped bootstrap
examples, secret references, Storage dashboard/CLI workflows, health states,
migration/backup/restore, and provider prerequisites. Embedding the runtime? Start with the
[`@caplets/core` package API](packages/core/README.md).

Comment thread
coderabbitai[bot] marked this conversation as resolved.
## Anonymous Telemetry

Caplets collects opt-out anonymous telemetry for product usage and reliability. The first eligible
Expand Down
Loading