Skip to content
Closed
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
1 change: 1 addition & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
"$ROOT/scripts/verify-no-secrets.sh" --staged
"$ROOT/scripts/generate-connector-contract.swift" --check
"$ROOT/scripts/generate-script-exec-contract.swift" --check
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Thank you for your interest in contributing. Please read the [Code of Conduct](C
## Requirements

- **macOS** with **Xcode 27** (Swift 6.4+)
- **Docker Desktop** (Python guest runtime, web crawler, and file extractor images)
- **Docker Desktop** (Go worker image for guests, web crawler, and file extractor)
- **Go 1.27.1+** (`brew install go`) for local diagnostics; guest compile runs in Docker
- Apple Developer account for code signing

## Getting started
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ We will acknowledge receipt and work on a fix before public disclosure when poss
Derrick runs LLM agents with tools on the user's Mac. The design assumes:

- **Untrusted model output** — tools and scripts are gated before execution.
- **Untrusted guest code** — Python plugins/scripts run in Docker with no network; the host performs HTTP.
- **Untrusted guest code** — Go plugins/scripts compile and run in Docker with no network; the host performs HTTP.
- **Untrusted remote content** — fetched HTML and tool output are sanitized before display.
- **Secrets stay on the host** — API keys and connector tokens live in Keychain or local `.env` (dev only); they are not injected into guest containers.

## Security controls

| Layer | Mechanism |
|-------|-----------|
| Script execution | Docker `--network none`, static Python verifier, LLM script reviewer |
| Script execution | Docker `--network none`, static Go verifier, in-container compile, LLM script reviewer |
| Network egress | Host HTTP client, egress blacklist, user approval for new destinations |
| Plugins | Factory build + review; hop-limited `http.request`; Keychain-attached auth |
| Inter-process | Code-signed XPC peers, HMAC-signed service messages (release: Keychain secret) |
Expand Down
2 changes: 1 addition & 1 deletion THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Derrick integrates with user-configured APIs. You supply your own keys and are s

## Runtime

- **Docker Desktop** — script and plugin execution use the `python:3.14.7` guest image (see `docs/adr-swift-script-runtime.md` for superseded Swift guest notes).
- **Docker Desktop** — script and plugin execution use the `derrick-worker:go-v1` guest image.

## Project license

Expand Down
15 changes: 0 additions & 15 deletions docker/guest-runtime/Dockerfile

This file was deleted.

3 changes: 3 additions & 0 deletions docker/worker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**/.git
**/.build
**/node_modules
33 changes: 33 additions & 0 deletions docker/worker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Unified Go worker image: web crawl, file extract (plugin guest binaries are copied per invoke).
# Build: docker build -f docker/worker/Dockerfile -t derrick-worker:go-v1 .
FROM golang:1.27.1 AS build

WORKDIR /src
COPY workers/go/go.mod workers/go/go.sum ./
RUN go mod download
COPY workers/go ./

RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/derrick-web-crawler ./cmd/derrick-crawler
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/derrick-file-extractor ./cmd/derrick-file-extractor

FROM debian:bookworm-slim

LABEL derrick.worker.binaries="crawler,extractor"

RUN apt-get update \
&& apt-get install -y --no-install-recommends poppler-utils ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --create-home --uid 10001 worker

COPY --from=build /usr/local/go /usr/local/go
COPY --from=build /out/derrick-web-crawler /usr/local/bin/derrick-web-crawler
COPY --from=build /out/derrick-file-extractor /usr/local/bin/derrick-file-extractor
RUN mkdir -p /data/in /data/out && chown -R worker:worker /data

ENV PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV GOROOT=/usr/local/go
ENV GOTOOLCHAIN=local
ENV CGO_ENABLED=0

USER worker
WORKDIR /home/worker
2 changes: 1 addition & 1 deletion docs/Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ This application is Protocol first. All major features must have a Protocol and

## Plugins
- Plugins are using the Agent Plugin standard
- Plugins run in the plugins docker containers as either Python or Go (Go is not yet supported)
- Plugins and `script_exec` run in the unified Go worker Docker image (`derrick-worker:go-v1`)
2 changes: 1 addition & 1 deletion master-todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Open: binary convert (xlsx) has no “here is your file” UI yet. Do not delete
Each `script_exec` / `plugin.invoke`:

1. Wait for the offline queue (max 1).
2. `docker create` a unique `derrick-guest-runtime-<uuid>` from `python:3.14.7`.
2. `docker create` a unique `derrick-guest-runtime-<uuid>` from `derrick-worker:go-v1`.
3. Run until the host hop loop is done (terminal envelope, error, or in-use lease TTL).
4. `docker rm -f` immediately — that is “I’m done.”
5. Release the queue slot so the next script can create at once.
Expand Down
157 changes: 0 additions & 157 deletions packages/DBRepository/Sources/DBRepository/DBRepositoryNews.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import Structure

public enum DatabaseSchema {
public static let latestVersion = 8
public static let latestVersion = 9

public static func migrationSQL(version: Int, isUp: Bool) throws -> String {
let migrationName = String(format: "%04d_%@", version, migrationFileBaseName(for: version))
Expand Down Expand Up @@ -39,6 +39,8 @@ public enum DatabaseSchema {
return "messaging_agent_handled"
case 8:
return "messaging_thread_default_profile"
case 9:
return "drop_news_readers"
default:
return "unknown"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CREATE TABLE IF NOT EXISTS news_readers (
mode TEXT NOT NULL,
max_count INTEGER NOT NULL,
schedule TEXT NOT NULL,
summary_text TEXT,
last_error TEXT,
last_fetched_at TEXT,
created_at TEXT NOT NULL,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
CREATE TABLE IF NOT EXISTS news_readers (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
topics_json TEXT NOT NULL DEFAULT '[]',
sources_json TEXT NOT NULL DEFAULT '[]',
mode TEXT NOT NULL,
max_count INTEGER NOT NULL,
schedule TEXT NOT NULL,
summary_text TEXT,
last_error TEXT,
last_fetched_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS news_items (
id TEXT PRIMARY KEY NOT NULL,
reader_id TEXT NOT NULL,
title TEXT NOT NULL,
source_url TEXT NOT NULL,
source_label TEXT NOT NULL,
summary TEXT,
published_at TEXT,
fetched_at TEXT NOT NULL,
UNIQUE(reader_id, source_url),
FOREIGN KEY(reader_id) REFERENCES news_readers(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_news_items_reader
ON news_items(reader_id, fetched_at DESC);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS news_items;
DROP TABLE IF EXISTS news_readers;

This file was deleted.

Loading
Loading