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
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Custom AP build context
CUSTOM_AP_CONTEXT=../custom-ap
CUSTOM_AP_DOCKERFILE=Dockerfile

# Test mode token (must match between test-runner and custom-ap)
TEST_MODE_TOKEN=ap-testbox-test-token

# Mastodon secrets (generate once via setup commands)
MASTODON_DB_PASSWORD=mastodon-pass
MASTODON_TEST_USERNAME=e2e-mastodon
MASTODON_TEST_EMAIL=e2e-mastodon@mastodon.localhost
MASTODON_TEST_PASSWORD=test-pass-mastodon
MASTODON_IMAGE_TAG=latest
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/certs
/misskey
/misskey
.env
114 changes: 114 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# AGENTS.md — ap-testbox

Docker Compose ActivityPub E2E testing environment. Uses [Iceshrimp](https://iceshrimp.dev) as the reference Fediverse implementation and supports running a custom AP system as a federation peer.

## Services

- **nginx**: Reverse proxy with SSL termination for 3 vhosts
- **iceshrimp**: Iceshrimp-JS v2026.5.1 (official Docker image, no build needed)
- **custom-ap**: Your custom ActivityPub implementation (built from local context)
- **test-runner**: TypeScript + Vitest E2E test suite
- **db**: PostgreSQL 16
- **redis**: Valkey 7 (Redis-compatible)
- **mastodon-web**: Mastodon v4.x Fediverse instance (official Docker image)
- **mastodon-streaming**: Mastodon streaming API
- **mastodon-sidekiq**: Mastodon background job processor (required for federation)
- **mastodon-db**: PostgreSQL 16 for Mastodon

## Domains (all via nginx on :4430)

| Domain | Proxy to | Purpose |
|---|---|---|
| `iceshrimp.localhost` | `iceshrimp:3000` | Primary Fediverse instance |
| `test-ap.localhost` | `custom-ap:12864` | Custom AP system |
| `shuttlepub.localhost` | `custom-ap:12864` | Legacy alias |
| `mastodon.localhost` | `mastodon-web:3000` | Mastodon federation peer |

## First-time setup (order matters)

```bash
cp .env.example .env # optional, override defaults
./gencert.sh # generates SSL certs for all domains
docker compose pull # pull iceshrimp, nginx, db, redis images
docker compose build # build custom-ap and test-runner
docker compose run --rm iceshrimp pnpm run init # runs DB migrations
docker compose up -d # start all services
docker compose run --rm test-runner # run E2E tests
```

## Directory layout

```
ap-testbox/
├── compose.yml # All services
├── gencert.sh # Fires up Docker-based mkcert
├── gencert/ # Dockerfile + mkcert.sh script
├── configs/
│ ├── nginx/confs/ # nginx SSL server blocks
│ │ ├── iceshrimp.conf
│ │ ├── test-ap.conf
│ │ └── shuttlepub.conf
│ └── iceshrimp/
│ ├── .config/
│ │ ├── default.yml # Iceshrimp application config
│ │ └── docker.env # DB env vars
│ ├── nginx/conf.d/ # nginx config mounted by iceshrimp
├── test-runner/ # E2E test suite (TypeScript + Vitest)
│ ├── Dockerfile
│ ├── package.json
│ ├── tsconfig.json
│ ├── vitest.config.ts
│ ├── src/
│ │ ├── config.ts
│ │ ├── wait.ts
│ │ ├── iceshrimp-api.ts
│ │ ├── custom-ap-client.ts
│ │ ├── http-signature.ts
│ │ └── activitypub.ts
│ └── tests/
│ ├── setup.ts
│ ├── follow.test.ts
│ └── note-delivery.test.ts
├── docs/
│ └── custom-ap-contract.md # Interface contract for custom AP
├── certs/ # gitignored, generated by gencert
└── misskey/ # gitignored (kept for reference, no longer needed)
```

## Common commands

| Action | Command |
|---|---|
| Build all images | `docker compose build` |
| Pull remote images | `docker compose pull` |
| Start all | `docker compose up -d` |
| Stop all | `docker compose down` |
| Run migration | `docker compose run --rm iceshrimp pnpm run init` |
| View iceshrimp logs | `docker compose logs -f iceshrimp` |
| Run E2E tests | `docker compose run --rm test-runner` |
| Rebuild test-runner | `docker compose build test-runner` |
| Access postgres | `docker compose exec db psql -U example-iceshrimp-user -d iceshrimp` |
| Custom AP health check | `curl -sk https://test-ap.localhost:4430/__test__/health` |
| View mastodon logs | `docker compose logs -f mastodon-web mastodon-sidekiq` |
| Mastodon DB setup | `docker compose run --rm mastodon-web bundle exec rails db:prepare` |
| Create Mastodon user | `docker compose run --rm mastodon-web bin/tootctl accounts create USERNAME --email EMAIL --confirmed` |

## Custom AP Contract

See [docs/custom-ap-contract.md](docs/custom-ap-contract.md) for the full interface contract.

The custom-ap service is built from `CUSTOM_AP_CONTEXT` (default: `../custom-ap`). Set via `.env`:

```env
CUSTOM_AP_CONTEXT=../my-ap-project
CUSTOM_AP_DOCKERFILE=Dockerfile
```

## Gotchas

- The `certs/` directory is in `.gitignore`. Always run `./gencert.sh` first.
- The nginx config blocks `/sw.js` (returns 404) on iceshrimp — service worker registration is disabled.
- Iceshrimp uses `pnpm run init` for DB migrations. Run this before starting for the first time.
- ActivityPub delivery is asynchronous. Tests have built-in polling with timeout.
- The test-runner uses `singleFork` mode — all tests run in sequence for stability.
- HTTP Signatures use draft-cavage-http-signatures with RSA-SHA256.
155 changes: 143 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,145 @@
# ap-testbox

Docker Compose ActivityPub E2E testing environment. Runs [Iceshrimp](https://iceshrimp.dev) as a reference Fediverse instance alongside your custom ActivityPub implementation, with an automated E2E test suite.

## Services

| Service | Image | Purpose |
|---|---|---|
| nginx | `nginx:1-alpine` | SSL reverse proxy for all vhosts |
| iceshrimp | `iceshrimp.dev/iceshrimp/iceshrimp:v2026.5.1` | Reference Fediverse instance |
| custom-ap | (build from your context) | Your AP implementation |
| test-runner | (build from `./test-runner`) | Vitest E2E test suite |
| db | `postgres:16-alpine` | PostgreSQL |
| redis | `valkey/valkey:7-alpine` | Redis-compatible cache |
| mastodon-web | `ghcr.io/mastodon/mastodon:latest` | Mastodon Fediverse instance (Puma) |
| mastodon-streaming | `ghcr.io/mastodon/mastodon-streaming:latest` | Mastodon streaming API |
| mastodon-sidekiq | `ghcr.io/mastodon/mastodon:latest` | Mastodon background jobs (federation) |
| mastodon-db | `postgres:16-alpine` | Mastodon PostgreSQL |

## Requirement

- [Docker](https://www.docker.com/)
- [Misskey (master)](https://github.com/misskey-dev/misskey)

### How to Run
1. Run `./gencert.sh`
2. Clone Misskey
- `git clone -b master https://github.com/misskey-dev/misskey.git`
3. Setup container
- `docker compose build`
- `docker compose run --rm misskey pnpm run init`
4. Start container
- `docker compose up -d`
5. Access to `https://misskey.local:4430` in your browser.
- [Docker Compose](https://docs.docker.com/compose/) (v2, included with Docker Desktop)
- Your custom ActivityPub implementation (for `custom-ap` service)

## Quick Start

```bash
# 1. Generate SSL certificates
./gencert.sh

# 2. Pull and build images
docker compose pull
docker compose build

# 3. Run database migrations
docker compose run --rm iceshrimp pnpm run init

# 4. Start all services
docker compose up -d

# 5. Run E2E tests
docker compose run --rm test-runner
```

Then access:
- **Iceshrimp**: `https://iceshrimp.localhost:4430`
- **Custom AP**: `https://test-ap.localhost:4430`
- **Mastodon**: `https://mastodon.localhost:4430`

## Custom AP Setup

Set the build context for your AP implementation in `.env`:

```env
CUSTOM_AP_CONTEXT=../my-ap-project
CUSTOM_AP_DOCKERFILE=Dockerfile
```

See [docs/custom-ap-contract.md](docs/custom-ap-contract.md) for required endpoints.

## Running E2E Tests

```bash
# Run all tests
docker compose run --rm test-runner

# Rebuild test-runner after changes
docker compose build test-runner
docker compose run --rm test-runner
```

## Mastodon Setup

```bash
# 1. Generate secrets (run from project root)
docker compose run --rm mastodon-web bundle exec rails secret
# ^ Save output as MASTODON_SECRET_KEY_BASE in .env
docker compose run --rm mastodon-web bundle exec rails secret
# ^ Save output as MASTODON_OTP_SECRET in .env
docker compose run --rm mastodon-web bundle exec rails mastodon:webpush:generate_vapid_key
# ^ Save VAPID_PRIVATE_KEY and VAPID_PUBLIC_KEY in .env

# 2. Prepare database (mastodon-db and redis must be running)
docker compose up -d mastodon-db redis
docker compose run --rm mastodon-web bundle exec rails db:prepare

# 3. Create test user
docker compose run --rm mastodon-web bin/tootctl accounts create "$MASTODON_TEST_USERNAME" --email "$MASTODON_TEST_EMAIL" --confirmed || true
docker compose run --rm mastodon-web bundle exec rails runner "
user = User.find_by!(email: ENV.fetch('MASTODON_TEST_EMAIL'))
user.update!(password: ENV.fetch('MASTODON_TEST_PASSWORD'), password_confirmation: ENV.fetch('MASTODON_TEST_PASSWORD'), confirmed_at: Time.now.utc)
"

# 4. Start all services and run tests
docker compose up -d
docker compose run --rm test-runner
```

Note: Secrets must be generated ONCE and stored in `.env`. Use `--insecure-dev-*` fallbacks only if you don't care about security (dev environment only).

## Common Commands

| Action | Command |
|---|---|
| Start all | `docker compose up -d` |
| Stop all | `docker compose down` |
| View logs | `docker compose logs -f iceshrimp` |
| Rebuild custom-ap | `docker compose build custom-ap` |
| Access DB | `docker compose exec db psql -U example-iceshrimp-user -d iceshrimp` |

## Architecture

```
┌──────────────┐ ┌──────────────────┐
│ nginx │────▶│ iceshrimp:3000 │
│ (SSL proxy) │ └────────┬─────────┘
│ │ │ federation
│ 3 vhosts │ ▼
│ │ ┌──────────────────┐
└──────┬───────┘ │ custom-ap:12864 │
│ └────────┬─────────┘
▼ │
┌──────────────────────────────┐
│ test-runner │
│ (orchestrates scenarios) │
│ - Iceshrimp REST API │
│ - AP protocol verification │
│ - Test endpoints for custom │
└──────────────────────────────┘
```

## Project Structure

```
configs/
├── nginx/confs/ # SSL vhost configs
└── iceshrimp/ # Iceshrimp settings
test-runner/ # E2E test suite
docs/ # Interface contracts
```

## License

MIT
Loading