@pgpm/encrypted-secrets-table 0.4.0 → 0.6.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/Makefile CHANGED
@@ -1,5 +1,5 @@
1
1
  EXTENSION = launchql-encrypted-secrets-table
2
- DATA = sql/launchql-encrypted-secrets-table--0.1.0.sql
2
+ DATA = sql/launchql-encrypted-secrets-table--0.5.0.sql
3
3
 
4
4
  PG_CONFIG = pg_config
5
5
  PGXS := $(shell $(PG_CONFIG) --pgxs)
package/README.md CHANGED
@@ -2,4 +2,363 @@
2
2
 
3
3
  Table-based encrypted secrets storage and retrieval.
4
4
 
5
- Extends encrypted secrets functionality with table-based storage, providing structured access to encrypted sensitive data.
5
+ ## Overview
6
+
7
+ `@pgpm/encrypted-secrets-table` provides the foundational storage layer for encrypted secrets management in PostgreSQL. This package creates the `secrets_schema.secrets_table` table that stores encrypted sensitive data such as API keys, passwords, tokens, and other credentials in a structured, secure format.
8
+
9
+ ## Features
10
+
11
+ - **Structured Storage**: Dedicated table for encrypted secrets with proper indexing
12
+ - **UUID-Based Ownership**: Links secrets to owning entities via UUID foreign keys
13
+ - **Dual Encryption Support**: Supports both bytea (binary) and text-encoded encrypted values
14
+ - **Unique Constraints**: Prevents duplicate secrets per owner
15
+ - **Automatic Hashing**: Trigger-based hashing for secret verification
16
+ - **Foundation Layer**: Provides storage for higher-level secrets management APIs
17
+
18
+ ## Installation
19
+
20
+ If you have `pgpm` installed:
21
+
22
+ ```bash
23
+ pgpm install @pgpm/encrypted-secrets-table
24
+ pgpm deploy
25
+ ```
26
+
27
+ This is a quick way to get started. The sections below provide more detailed installation options.
28
+
29
+ ### Prerequisites
30
+
31
+ ```bash
32
+ # Install pgpm globally
33
+ npm install -g pgpm
34
+
35
+ # Start PostgreSQL
36
+ pgpm docker start
37
+
38
+ # Set environment variables
39
+ eval "$(pgpm env)"
40
+ ```
41
+
42
+ ### Deploy
43
+
44
+ #### Option 1: Deploy by installing with pgpm
45
+
46
+ ```bash
47
+ pgpm install @pgpm/encrypted-secrets-table
48
+ pgpm deploy
49
+ ```
50
+
51
+ #### Option 2: Deploy from Package Directory
52
+
53
+ ```bash
54
+ cd packages/security/encrypted-secrets-table
55
+ pgpm deploy --createdb
56
+ ```
57
+
58
+ #### Option 3: Deploy from Workspace Root
59
+
60
+ ```bash
61
+ # Install workspace dependencies
62
+ pnpm install
63
+
64
+ # Deploy with dependencies
65
+ pgpm deploy mydb1 --yes --createdb
66
+ ```
67
+
68
+ ## Database Schema
69
+
70
+ ### secrets_schema.secrets_table
71
+
72
+ The core table for storing encrypted secrets:
73
+
74
+ ```sql
75
+ CREATE TABLE secrets_schema.secrets_table (
76
+ id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
77
+ secrets_owned_field uuid NOT NULL, -- Owner entity ID
78
+ name text NOT NULL, -- Secret name/identifier
79
+ secrets_value_field bytea NULL, -- Binary encrypted value
80
+ secrets_enc_field text NULL, -- Text-encoded encrypted value
81
+ UNIQUE(secrets_owned_field, name) -- One secret per name per owner
82
+ );
83
+ ```
84
+
85
+ **Columns:**
86
+ - `id`: Unique identifier for the secret record
87
+ - `secrets_owned_field`: UUID of the entity that owns this secret (e.g., user ID, organization ID)
88
+ - `name`: Human-readable name for the secret (e.g., "github_token", "stripe_api_key")
89
+ - `secrets_value_field`: Binary encrypted value (bytea format)
90
+ - `secrets_enc_field`: Text-encoded encrypted value (for PGP armor format)
91
+
92
+ **Constraints:**
93
+ - Primary key on `id`
94
+ - Unique constraint on `(secrets_owned_field, name)` ensures each owner can have only one secret with a given name
95
+
96
+ ### Triggers
97
+
98
+ #### hash_secrets
99
+
100
+ Automatically hashes secrets for verification purposes:
101
+
102
+ ```sql
103
+ CREATE TRIGGER hash_secrets
104
+ BEFORE INSERT OR UPDATE ON secrets_schema.secrets_table
105
+ FOR EACH ROW
106
+ EXECUTE FUNCTION secrets_schema.hash_secrets_trigger();
107
+ ```
108
+
109
+ This trigger ensures secrets are properly hashed before storage, enabling verification without exposing the raw values.
110
+
111
+ ## Usage
112
+
113
+ ### Storing a Secret
114
+
115
+ ```sql
116
+ -- Insert an encrypted secret
117
+ INSERT INTO secrets_schema.secrets_table (
118
+ secrets_owned_field,
119
+ name,
120
+ secrets_value_field
121
+ ) VALUES (
122
+ 'user-uuid-here',
123
+ 'api_key',
124
+ pgp_sym_encrypt('my-secret-value', 'encryption-password')
125
+ );
126
+ ```
127
+
128
+ ### Retrieving a Secret
129
+
130
+ ```sql
131
+ -- Get encrypted secret
132
+ SELECT
133
+ id,
134
+ name,
135
+ pgp_sym_decrypt(secrets_value_field, 'encryption-password') AS decrypted_value
136
+ FROM secrets_schema.secrets_table
137
+ WHERE secrets_owned_field = 'user-uuid-here'
138
+ AND name = 'api_key';
139
+ ```
140
+
141
+ ### Updating a Secret
142
+
143
+ ```sql
144
+ -- Update existing secret
145
+ UPDATE secrets_schema.secrets_table
146
+ SET secrets_value_field = pgp_sym_encrypt('new-secret-value', 'encryption-password')
147
+ WHERE secrets_owned_field = 'user-uuid-here'
148
+ AND name = 'api_key';
149
+ ```
150
+
151
+ ### Deleting a Secret
152
+
153
+ ```sql
154
+ -- Remove a secret
155
+ DELETE FROM secrets_schema.secrets_table
156
+ WHERE secrets_owned_field = 'user-uuid-here'
157
+ AND name = 'api_key';
158
+ ```
159
+
160
+ ## Common Patterns
161
+
162
+ ### Multi-Tenant Secrets
163
+
164
+ ```sql
165
+ -- Each organization has its own secrets
166
+ INSERT INTO secrets_schema.secrets_table (
167
+ secrets_owned_field,
168
+ name,
169
+ secrets_value_field
170
+ ) VALUES
171
+ ('org-1-uuid', 'aws_access_key', pgp_sym_encrypt('...', 'password')),
172
+ ('org-1-uuid', 'aws_secret_key', pgp_sym_encrypt('...', 'password')),
173
+ ('org-2-uuid', 'aws_access_key', pgp_sym_encrypt('...', 'password'));
174
+ ```
175
+
176
+ ### User-Specific Secrets
177
+
178
+ ```sql
179
+ -- Each user has their own API tokens
180
+ INSERT INTO secrets_schema.secrets_table (
181
+ secrets_owned_field,
182
+ name,
183
+ secrets_value_field
184
+ ) VALUES
185
+ ('user-1-uuid', 'github_token', pgp_sym_encrypt('...', 'password')),
186
+ ('user-2-uuid', 'github_token', pgp_sym_encrypt('...', 'password'));
187
+ ```
188
+
189
+ ### Listing All Secrets for an Owner
190
+
191
+ ```sql
192
+ -- Get all secret names for an owner (without values)
193
+ SELECT id, name
194
+ FROM secrets_schema.secrets_table
195
+ WHERE secrets_owned_field = 'user-uuid-here'
196
+ ORDER BY name;
197
+ ```
198
+
199
+ ## Integration with Other Packages
200
+
201
+ ### With @pgpm/encrypted-secrets
202
+
203
+ The `@pgpm/encrypted-secrets` package builds on this storage layer to provide:
204
+ - High-level API functions for secret management
205
+ - Role-based access control
206
+ - Encryption/decryption helpers
207
+ - Secret verification functions
208
+
209
+ ```sql
210
+ -- @pgpm/encrypted-secrets provides functions like:
211
+ SELECT encrypted_secrets.secrets_getter('owner-uuid', 'secret-name');
212
+ SELECT encrypted_secrets.secrets_upsert('owner-uuid', 'secret-name', 'value');
213
+ ```
214
+
215
+ ### With Application Tables
216
+
217
+ Link secrets to your application entities:
218
+
219
+ ```sql
220
+ -- Users table with secrets
221
+ CREATE TABLE users (
222
+ id uuid PRIMARY KEY,
223
+ email text,
224
+ -- Secrets stored in secrets_schema.secrets_table
225
+ -- with secrets_owned_field = users.id
226
+ );
227
+
228
+ -- Get user's secrets
229
+ SELECT s.*
230
+ FROM users u
231
+ JOIN secrets_schema.secrets_table s ON s.secrets_owned_field = u.id
232
+ WHERE u.email = 'user@example.com';
233
+ ```
234
+
235
+ ## Security Considerations
236
+
237
+ 1. **Encryption Required**: Never store plaintext secrets in this table
238
+ 2. **Access Control**: Use PostgreSQL RLS policies to restrict access
239
+ 3. **Encryption Keys**: Store encryption passwords securely (not in database)
240
+ 4. **Audit Logging**: Consider logging access to secrets table
241
+ 5. **Key Rotation**: Plan for periodic re-encryption with new keys
242
+
243
+ ### Row-Level Security Example
244
+
245
+ ```sql
246
+ -- Enable RLS
247
+ ALTER TABLE secrets_schema.secrets_table ENABLE ROW LEVEL SECURITY;
248
+
249
+ -- Users can only access their own secrets
250
+ CREATE POLICY user_secrets ON secrets_schema.secrets_table
251
+ FOR ALL
252
+ TO authenticated
253
+ USING (secrets_owned_field = jwt_public.current_user_id());
254
+
255
+ -- Administrators can access all secrets
256
+ CREATE POLICY admin_secrets ON secrets_schema.secrets_table
257
+ FOR ALL
258
+ TO administrator
259
+ USING (true);
260
+ ```
261
+
262
+ ## Best Practices
263
+
264
+ 1. **Use Unique Names**: Choose descriptive, unique names for each secret
265
+ 2. **Consistent Ownership**: Use the same UUID scheme for `secrets_owned_field` across your application
266
+ 3. **Binary vs Text**: Use `secrets_value_field` (bytea) for better performance, `secrets_enc_field` (text) for PGP armor format
267
+ 4. **Don't Log Secrets**: Ensure database logs don't capture decrypted values
268
+ 5. **Regular Cleanup**: Remove secrets when owners are deleted
269
+
270
+ ## Dependencies
271
+
272
+ - `@pgpm/verify`: Verification utilities
273
+
274
+ ## Testing
275
+
276
+ ```bash
277
+ pnpm test
278
+ ```
279
+
280
+ ## Development
281
+
282
+ See the [Development](#development) section below for information on working with this package.
283
+
284
+ ---
285
+
286
+ ## Development
287
+
288
+ ### **Before You Begin**
289
+
290
+ ```bash
291
+ # 1. Install pgpm
292
+ npm install -g pgpm
293
+
294
+ # 2. Start Postgres (Docker or local)
295
+ pgpm docker start
296
+
297
+ # 3. Load PG* environment variables (PGHOST, PGUSER, ...)
298
+ eval "$(pgpm env)"
299
+ ```
300
+
301
+ ---
302
+
303
+ ### **Starting a New Project**
304
+
305
+ ```bash
306
+ # 1. Create a workspace
307
+ pgpm init --workspace
308
+ cd my-app
309
+
310
+ # 2. Create your first module
311
+ pgpm init
312
+
313
+ # 3. Add a migration
314
+ pgpm add some_change
315
+
316
+ # 4. Deploy (auto-creates database)
317
+ pgpm deploy --createdb
318
+ ```
319
+
320
+ ---
321
+
322
+ ### **Working With an Existing Project**
323
+
324
+ ```bash
325
+ # 1. Clone and enter the project
326
+ git clone <repo> && cd <project>
327
+
328
+ # 2. Install dependencies
329
+ pnpm install
330
+
331
+ # 3. Deploy locally
332
+ pgpm deploy --createdb
333
+ ```
334
+
335
+ ---
336
+
337
+ ### **Testing a Module Inside a Workspace**
338
+
339
+ ```bash
340
+ # 1. Install workspace deps
341
+ pnpm install
342
+
343
+ # 2. Enter the module directory
344
+ cd packages/<some-module>
345
+
346
+ # 3. Run tests in watch mode
347
+ pnpm test:watch
348
+ ```
349
+
350
+ ## Related Tooling
351
+
352
+ * [pgpm](https://github.com/launchql/launchql/tree/main/packages/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
353
+ * [pgsql-test](https://github.com/launchql/launchql/tree/main/packages/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
354
+ * [supabase-test](https://github.com/launchql/launchql/tree/main/packages/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
355
+ * [graphile-test](https://github.com/launchql/launchql/tree/main/packages/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
356
+ * [pgsql-parser](https://github.com/launchql/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
357
+ * [libpg-query-node](https://github.com/launchql/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
358
+ * [pg-proto-parser](https://github.com/launchql/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
359
+
360
+ ## Disclaimer
361
+
362
+ AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
363
+
364
+ No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
@@ -1,6 +1,6 @@
1
1
  # launchql-encrypted-secrets-table extension
2
2
  comment = 'launchql-encrypted-secrets-table extension'
3
- default_version = '0.1.0'
3
+ default_version = '0.5.0'
4
4
  module_pathname = '$libdir/launchql-encrypted-secrets-table'
5
5
  requires = 'pgcrypto,plpgsql,uuid-ossp,launchql-verify'
6
6
  relocatable = false
package/package.json CHANGED
@@ -1,28 +1,28 @@
1
1
  {
2
2
  "name": "@pgpm/encrypted-secrets-table",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Table-based encrypted secrets storage and retrieval",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "scripts": {
9
- "bundle": "lql package",
9
+ "bundle": "pgpm package",
10
10
  "test": "jest",
11
11
  "test:watch": "jest --watch"
12
12
  },
13
13
  "dependencies": {
14
- "@pgpm/verify": "0.4.0"
14
+ "@pgpm/verify": "0.6.0"
15
15
  },
16
16
  "devDependencies": {
17
- "@launchql/cli": "^4.9.0"
17
+ "pgpm": "^0.2.0"
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "https://github.com/launchql/extensions"
21
+ "url": "https://github.com/launchql/pgpm-modules"
22
22
  },
23
- "homepage": "https://github.com/launchql/extensions",
23
+ "homepage": "https://github.com/launchql/pgpm-modules",
24
24
  "bugs": {
25
- "url": "https://github.com/launchql/extensions/issues"
25
+ "url": "https://github.com/launchql/pgpm-modules/issues"
26
26
  },
27
- "gitHead": "cc9f52a335caa6e21ee7751b04b77c84ce6cb809"
27
+ "gitHead": "c7d0eae588d7a764b382a330c8b853b341b13fb2"
28
28
  }
File without changes