Skip to content

Commit c6a9b29

Browse files
authored
Merge pull request #15 from wataruoguchi/crypto-shredding
Add the crypto shredding feature
2 parents ede3993 + 1bb7130 commit c6a9b29

77 files changed

Lines changed: 32824 additions & 431 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm
1+
FROM mcr.microsoft.com/devcontainers/javascript-node:24-trixie
22

33
RUN apt-get update \
44
&& apt-get install -y pgcli ack mkcert \

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
22
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node-postgres
33
{
4-
"name": "Node.js & PostgreSQL",
4+
"name": "Emmett Libs",
55
"dockerComposeFile": "docker-compose.yml",
66
"service": "app",
77
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",

.github/workflows/ci.yml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@ on:
1010

1111
jobs:
1212
quality:
13-
name: Quality Checks
13+
name: Quality Checks - ${{ matrix.package }}
1414
runs-on: ubuntu-latest
15+
strategy:
16+
matrix:
17+
package:
18+
- emmett-event-store-kysely
19+
- emmett-crypto-shredding
20+
- emmett-crypto-shredding-kysely
1521
defaults:
1622
run:
17-
working-directory: ./packages/emmett-event-store-kysely
23+
working-directory: ./packages/${{ matrix.package }}
1824

1925
steps:
2026
- name: Checkout code
@@ -27,7 +33,7 @@ jobs:
2733
with:
2834
node-version: '20'
2935
cache: 'npm'
30-
cache-dependency-path: './packages/emmett-event-store-kysely/package-lock.json'
36+
cache-dependency-path: './packages/${{ matrix.package }}/package-lock.json'
3137

3238
- name: Install dependencies
3339
run: npm ci
@@ -39,17 +45,23 @@ jobs:
3945
run: npm run build
4046

4147
release:
42-
name: Release
48+
name: Release - ${{ matrix.package }}
4349
runs-on: ubuntu-latest
4450
needs: quality
4551
if: github.ref == 'refs/heads/main'
52+
strategy:
53+
matrix:
54+
package:
55+
- emmett-event-store-kysely
56+
- emmett-crypto-shredding
57+
- emmett-crypto-shredding-kysely
4658
permissions:
4759
contents: write
4860
issues: write
4961
pull-requests: write
5062
defaults:
5163
run:
52-
working-directory: ./packages/emmett-event-store-kysely
64+
working-directory: ./packages/${{ matrix.package }}
5365

5466
steps:
5567
- name: Checkout code
@@ -64,7 +76,7 @@ jobs:
6476
node-version: '20'
6577
registry-url: 'https://registry.npmjs.org'
6678
cache: 'npm'
67-
cache-dependency-path: './packages/emmett-event-store-kysely/package-lock.json'
79+
cache-dependency-path: './packages/${{ matrix.package }}/package-lock.json'
6880

6981
- name: Install dependencies
7082
run: npm ci

.github/workflows/docs.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Deploy Documentation
2+
on:
3+
push:
4+
branches: [main]
5+
paths:
6+
- 'docs/**'
7+
- '.vitepress/**'
8+
- 'package.json'
9+
- 'package-lock.json'
10+
workflow_dispatch: # Allow manual triggering
11+
12+
permissions:
13+
contents: read
14+
pages: write
15+
id-token: write
16+
17+
concurrency:
18+
group: "pages"
19+
cancel-in-progress: false
20+
21+
jobs:
22+
build:
23+
name: Build Documentation
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout code
27+
uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: '20'
35+
cache: 'npm'
36+
cache-dependency-path: './package-lock.json'
37+
38+
- name: Install dependencies
39+
run: npm ci
40+
41+
- name: Build VitePress site
42+
run: npm run docs:build
43+
44+
- name: Setup Pages
45+
uses: actions/configure-pages@v4
46+
47+
- name: Upload artifact
48+
uses: actions/upload-pages-artifact@v3
49+
with:
50+
path: './docs/.vitepress/dist'
51+
52+
deploy:
53+
name: Deploy to GitHub Pages
54+
runs-on: ubuntu-latest
55+
needs: build
56+
environment:
57+
name: github-pages
58+
url: ${{ steps.deployment.outputs.page_url }}
59+
steps:
60+
- name: Deploy to GitHub Pages
61+
id: deployment
62+
uses: actions/deploy-pages@v4
63+

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ lerna-debug.log*
2727
# misc
2828
.DS_Store
2929
*.ignored.*
30-
coverage/
30+
coverage/
31+
docs/.vitepress/
32+

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# @wataruoguchi/emmett-libs
2+
3+
Event sourcing libraries built on [Emmett](https://github.com/event-driven-io/emmett).
4+
5+
## 📚 Documentation
6+
7+
**👉 [View Full Documentation →](https://wataruoguchi.github.io/emmett-libs/)**
8+
9+
## 📦 Packages
10+
11+
- **[@wataruoguchi/emmett-event-store-kysely](./packages/emmett-event-store-kysely)** - Kysely-based event store with PostgreSQL
12+
- **[@wataruoguchi/emmett-crypto-shredding](./packages/emmett-crypto-shredding)** - Crypto shredding for event streams
13+
- **[@wataruoguchi/emmett-crypto-shredding-kysely](./packages/emmett-crypto-shredding-kysely)** - Kysely adapters for crypto shredding
14+
15+
## 📖 Example Project
16+
17+
The [`example`](./example) directory contains a working SaaS application demonstrating how to use these packages together:
18+
19+
- **Event Store Integration** - See how `@wataruoguchi/emmett-event-store-kysely` is used for event sourcing with PostgreSQL
20+
- Located in `example/src/modules/*/application/event-sourcing/`
21+
- Example modules: `cart`, `generator`, `tenant`
22+
23+
- **Crypto Shredding Implementation** - Complete example of `@wataruoguchi/emmett-crypto-shredding` with Kysely adapters
24+
- See `example/src/modules/generator/application/event-sourcing/crypto/` for crypto adapters usage
25+
- Check `example/src/modules/generator/tests/generator.crypto.e2e.spec.ts` for comprehensive test coverage including:
26+
- Key scopes (stream, type, tenant)
27+
- Multi-tenant isolation
28+
- Key rotation and crypto shredding
29+
- Graceful error handling
30+
31+
- **Database Migrations** - Example migrations for both event store and crypto shredding tables
32+
- Event store tables in `example/database/migrations/`
33+
- Crypto shredding tables in `packages/emmett-crypto-shredding-kysely/database/migrations/`
34+
35+
- **Projections** - Examples of building read models with snapshot projections
36+
- See `example/src/modules/generator/application/event-sourcing/generator.event-handler.ts`
37+
- Example read model migrations in `example/database/migrations/`
38+
39+
## 📄 License
40+
41+
MIT
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
outline: deep
3+
---
4+
5+
# @wataruoguchi/emmett-crypto-shredding-kysely
6+
7+
Kysely adapters for [Emmett Crypto Shredding](./emmett-crypto-shredding), providing PostgreSQL-backed implementations for key storage and policy resolution.
8+
9+
## Installation
10+
11+
```bash
12+
npm install @wataruoguchi/emmett-crypto-shredding-kysely @wataruoguchi/emmett-crypto-shredding kysely pg
13+
```
14+
15+
## Quick Start
16+
17+
### 1. Run Database Migration
18+
19+
Copy the migration file from `database/migrations/` to your migrations directory.
20+
21+
### 2. Create Key Management and Policy Resolver
22+
23+
```typescript
24+
import {
25+
createKeyManagement,
26+
createPolicyResolver
27+
} from '@wataruoguchi/emmett-crypto-shredding-kysely';
28+
29+
const keyManagement = createKeyManagement(db);
30+
const policyResolver = createPolicyResolver(db, logger);
31+
```
32+
33+
### 3. Set Up Encryption Policies
34+
35+
```typescript
36+
import { createDefaultPolicies, createPolicies } from '@wataruoguchi/emmett-crypto-shredding-kysely';
37+
38+
// Option 1: Use default policies
39+
// Creates policies for common stream types:
40+
// - user-data: AES-GCM, 180 day rotation, stream scope
41+
// - audit-log: AES-GCM, 365 day rotation, stream scope
42+
await createDefaultPolicies(db, 'tenant-123');
43+
44+
// Option 2: Create custom policies
45+
await createPolicies(db, [
46+
{
47+
policyId: 'tenant-123-user-data',
48+
partition: 'tenant-123',
49+
streamTypeClass: 'user-data',
50+
encryptionAlgorithm: 'AES-GCM',
51+
keyRotationIntervalDays: 180,
52+
keyScope: 'stream',
53+
},
54+
]);
55+
```
56+
57+
### 4. Create Encrypted Event Store
58+
59+
```typescript
60+
import { createCryptoEventStore } from '@wataruoguchi/emmett-crypto-shredding';
61+
import { getKyselyEventStore } from '@wataruoguchi/emmett-event-store-kysely';
62+
63+
const baseEventStore = getKyselyEventStore({ db, logger });
64+
65+
const cryptoEventStore = createCryptoEventStore({
66+
baseEventStore,
67+
keyManagement,
68+
policyResolver,
69+
buildAAD: (ctx) => JSON.stringify({
70+
partition: ctx.partition,
71+
streamId: ctx.streamId,
72+
streamType: ctx.streamType,
73+
eventType: ctx.eventType,
74+
}),
75+
logger,
76+
});
77+
```
78+
79+
## API Reference
80+
81+
### Key Management
82+
83+
```typescript
84+
// Get or create active key
85+
const key = await keyManagement.getActiveKey({
86+
partition: 'tenant-123',
87+
keyRef: 'user-data',
88+
});
89+
90+
// Rotate key
91+
await keyManagement.rotateKey({
92+
partition: 'tenant-123',
93+
keyRef: 'user-data',
94+
});
95+
96+
// Destroy all keys for a partition (crypto shredding)
97+
await keyManagement.destroyPartitionKeys({
98+
partition: 'tenant-123',
99+
});
100+
```
101+
102+
### Policy Management
103+
104+
```typescript
105+
// Create policies
106+
await createPolicies(db, policies);
107+
108+
// Update policy
109+
await updatePolicy(db, policyId, partition, {
110+
encryptionAlgorithm: 'AES-GCM',
111+
keyRotationIntervalDays: 365,
112+
});
113+
114+
// List policies
115+
const policies = await listPolicies(db, partition);
116+
117+
// Delete policy
118+
await deletePolicy(db, policyId, partition);
119+
```
120+
121+
## See Also
122+
123+
- [Crypto Shredding Core](./emmett-crypto-shredding) - Core encryption functionality
124+
- [Event Store Kysely](./emmett-event-store-kysely) - Base event store implementation
125+
- [Example Application](https://github.com/wataruoguchi/emmett-libs/tree/main/example) - Complete working example

0 commit comments

Comments
 (0)