@bostonuniversity/buwp-local 0.4.0 → 0.4.1
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/.buwp-local.json +22 -0
- package/.env.local.example +26 -0
- package/USAGE.md +31 -5
- package/lib/commands/init.js +4 -0
- package/lib/commands/start.js +7 -2
- package/lib/compose-generator.js +21 -28
- package/package.json +2 -2
- package/plan-environmentBasedCredentials.prompt.md +57 -0
package/.buwp-local.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projectName": "buwp-local",
|
|
3
|
+
"image": "ghcr.io/bu-ist/bu-wp-docker-mod_shib:arm64-latest",
|
|
4
|
+
"hostname": "jaydub.local",
|
|
5
|
+
"multisite": true,
|
|
6
|
+
"services": {
|
|
7
|
+
"redis": true,
|
|
8
|
+
"s3proxy": true,
|
|
9
|
+
"shibboleth": true
|
|
10
|
+
},
|
|
11
|
+
"ports": {
|
|
12
|
+
"http": 80,
|
|
13
|
+
"https": 443,
|
|
14
|
+
"db": 3306,
|
|
15
|
+
"redis": 6379
|
|
16
|
+
},
|
|
17
|
+
"mappings": [],
|
|
18
|
+
"env": {
|
|
19
|
+
"WP_DEBUG": true,
|
|
20
|
+
"XDEBUG": false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# BU WordPress Local Development Environment Variables
|
|
2
|
+
# Copy this file to .env.local and fill in your actual credentials
|
|
3
|
+
# NEVER commit .env.local to version control!
|
|
4
|
+
|
|
5
|
+
# Database Credentials
|
|
6
|
+
WORDPRESS_DB_PASSWORD=password
|
|
7
|
+
DB_ROOT_PASSWORD=rootpassword
|
|
8
|
+
|
|
9
|
+
# Shibboleth Configuration (if enabled)
|
|
10
|
+
SP_ENTITY_ID=https://your-sp-entity-id
|
|
11
|
+
IDP_ENTITY_ID=https://shib-test.bu.edu/idp/shibboleth
|
|
12
|
+
SHIB_IDP_LOGOUT=https://shib-test.bu.edu/idp/logout.jsp
|
|
13
|
+
SHIB_SP_KEY=your-private-key-here
|
|
14
|
+
SHIB_SP_CERT=your-certificate-here
|
|
15
|
+
|
|
16
|
+
# AWS S3 Configuration (if enabled)
|
|
17
|
+
S3_UPLOADS_BUCKET=your-bucket-name
|
|
18
|
+
S3_UPLOADS_REGION=us-east-1
|
|
19
|
+
S3_UPLOADS_ACCESS_KEY_ID=AKIA...
|
|
20
|
+
S3_UPLOADS_SECRET_ACCESS_KEY=your-secret-key
|
|
21
|
+
S3_ACCESS_RULES_TABLE=your-access-rules-table
|
|
22
|
+
|
|
23
|
+
# OLAP Configuration (if using S3 Object Lambda)
|
|
24
|
+
OLAP=your-olap-name
|
|
25
|
+
OLAP_ACCT_NBR=123456789
|
|
26
|
+
OLAP_REGION=us-east-1
|
package/USAGE.md
CHANGED
|
@@ -51,7 +51,13 @@ Edit `.buwp-local.json` to map your local repository into the container:
|
|
|
51
51
|
|
|
52
52
|
### 4. Create `.env.local` for secrets
|
|
53
53
|
|
|
54
|
-
Create `.env.local` (never commit this file!):
|
|
54
|
+
Create `.env.local` (never commit this file!) or copy from the example:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cp .env.local.example .env.local
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then edit `.env.local` with your actual credentials:
|
|
55
61
|
|
|
56
62
|
```bash
|
|
57
63
|
# Database
|
|
@@ -70,6 +76,7 @@ S3_UPLOADS_BUCKET=your-bucket
|
|
|
70
76
|
S3_UPLOADS_REGION=us-east-1
|
|
71
77
|
S3_UPLOADS_ACCESS_KEY_ID=your-access-key
|
|
72
78
|
S3_UPLOADS_SECRET_ACCESS_KEY=your-secret-key
|
|
79
|
+
S3_ACCESS_RULES_TABLE=your-access-rules-table
|
|
73
80
|
|
|
74
81
|
# OLAP
|
|
75
82
|
OLAP=your-olap-name
|
|
@@ -77,6 +84,8 @@ OLAP_ACCT_NBR=your-account-number
|
|
|
77
84
|
OLAP_REGION=us-east-1
|
|
78
85
|
```
|
|
79
86
|
|
|
87
|
+
**Important:** Credentials are read directly from `.env.local` by Docker Compose. They are never written to the generated `docker-compose.yml` file, making it safe to review or share the generated compose file without exposing secrets.
|
|
88
|
+
|
|
80
89
|
### 5. Add hostname to /etc/hosts
|
|
81
90
|
|
|
82
91
|
```bash
|
|
@@ -226,10 +235,27 @@ Map your local code into the container:
|
|
|
226
235
|
## Security Best Practices
|
|
227
236
|
|
|
228
237
|
1. **Never commit `.env.local`** - This file contains secrets
|
|
229
|
-
2. **Never commit `.buwp-local/`** - This contains generated files
|
|
230
|
-
3. **Do commit `.buwp-local.json`** - This is your configuration template
|
|
231
|
-
4. **Use environment variables for all secrets**
|
|
232
|
-
5. **
|
|
238
|
+
2. **Never commit `.buwp-local/`** - This directory contains generated files
|
|
239
|
+
3. **Do commit `.buwp-local.json`** - This is your configuration template (no secrets)
|
|
240
|
+
4. **Use environment variables for all secrets** - Credentials stay in `.env.local` and are never written to generated files
|
|
241
|
+
5. **Review generated compose files** - The generated `docker-compose.yml` only contains variable references like `${WORDPRESS_DB_PASSWORD}`, not actual credentials
|
|
242
|
+
6. **Copy `.env.local.example`** - Use the provided template to create your `.env.local` file
|
|
243
|
+
7. **Consider using macOS Keychain** for even better security (future feature)
|
|
244
|
+
|
|
245
|
+
### How Credentials Work
|
|
246
|
+
|
|
247
|
+
buwp-local uses Docker Compose's native environment variable interpolation:
|
|
248
|
+
|
|
249
|
+
1. **You provide** credentials in `.env.local`
|
|
250
|
+
2. **buwp-local generates** `docker-compose.yml` with variable references like `${VAR_NAME}`
|
|
251
|
+
3. **Docker Compose reads** `.env.local` at runtime and substitutes the values
|
|
252
|
+
4. **Your secrets never** get written to any generated files
|
|
253
|
+
|
|
254
|
+
This means:
|
|
255
|
+
- ✅ Generated compose files are safe to review or share
|
|
256
|
+
- ✅ No credentials in version control (even accidentally)
|
|
257
|
+
- ✅ Industry-standard Docker Compose pattern
|
|
258
|
+
- ✅ Simple and secure
|
|
233
259
|
|
|
234
260
|
## File Structure
|
|
235
261
|
|
package/lib/commands/init.js
CHANGED
|
@@ -133,6 +133,10 @@ async function initCommand(options) {
|
|
|
133
133
|
name: 'hostname',
|
|
134
134
|
message: 'Hostname',
|
|
135
135
|
initial: (prev, values) => {
|
|
136
|
+
// For sandbox, use just username.local; for other types include project name
|
|
137
|
+
if (values.projectType === 'sandbox') {
|
|
138
|
+
return `${userName}.local`;
|
|
139
|
+
}
|
|
136
140
|
return `${userName}-${values.projectName}.local`;
|
|
137
141
|
},
|
|
138
142
|
validate: value => {
|
package/lib/commands/start.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { execSync } from 'child_process';
|
|
7
7
|
import path from 'path';
|
|
8
|
-
import
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { loadConfig, validateConfig, ENV_FILE_NAME } from '../config.js';
|
|
9
10
|
import { generateComposeFile } from '../compose-generator.js';
|
|
10
11
|
|
|
11
12
|
async function startCommand(options) {
|
|
@@ -60,9 +61,13 @@ async function startCommand(options) {
|
|
|
60
61
|
const composeDir = path.dirname(composePath);
|
|
61
62
|
const projectName = config.projectName || 'buwp-local';
|
|
62
63
|
|
|
64
|
+
// Check if .env.local exists and build env-file flag
|
|
65
|
+
const envFilePath = path.join(projectPath, ENV_FILE_NAME);
|
|
66
|
+
const envFileFlag = fs.existsSync(envFilePath) ? `--env-file ${envFilePath}` : '';
|
|
67
|
+
|
|
63
68
|
try {
|
|
64
69
|
execSync(
|
|
65
|
-
`docker compose -p ${projectName} -f ${composePath} up -d`,
|
|
70
|
+
`docker compose -p ${projectName} ${envFileFlag} -f ${composePath} up -d`,
|
|
66
71
|
{
|
|
67
72
|
cwd: composeDir,
|
|
68
73
|
stdio: 'inherit'
|
package/lib/compose-generator.js
CHANGED
|
@@ -57,9 +57,6 @@ function generateComposeConfig(config) {
|
|
|
57
57
|
* @returns {object} Database service config
|
|
58
58
|
*/
|
|
59
59
|
function generateDbService(config, dbVolumeName) {
|
|
60
|
-
const dbPassword = config.db?.password || 'password';
|
|
61
|
-
const rootPassword = config.db?.rootPassword || 'rootpassword';
|
|
62
|
-
|
|
63
60
|
return {
|
|
64
61
|
image: 'mariadb:latest',
|
|
65
62
|
restart: 'always',
|
|
@@ -67,8 +64,8 @@ function generateDbService(config, dbVolumeName) {
|
|
|
67
64
|
environment: {
|
|
68
65
|
MYSQL_DATABASE: 'wordpress',
|
|
69
66
|
MYSQL_USER: 'wordpress',
|
|
70
|
-
MYSQL_PASSWORD:
|
|
71
|
-
MYSQL_ROOT_PASSWORD:
|
|
67
|
+
MYSQL_PASSWORD: '${WORDPRESS_DB_PASSWORD:-password}',
|
|
68
|
+
MYSQL_ROOT_PASSWORD: '${DB_ROOT_PASSWORD:-rootpassword}'
|
|
72
69
|
},
|
|
73
70
|
ports: [`${config.ports.db}:3306`],
|
|
74
71
|
networks: ['wp-network']
|
|
@@ -91,7 +88,7 @@ function generateWordPressService(config, wpVolumeName) {
|
|
|
91
88
|
const environment = {
|
|
92
89
|
WORDPRESS_DB_HOST: 'db:3306',
|
|
93
90
|
WORDPRESS_DB_USER: 'wordpress',
|
|
94
|
-
WORDPRESS_DB_PASSWORD:
|
|
91
|
+
WORDPRESS_DB_PASSWORD: '${WORDPRESS_DB_PASSWORD:-password}',
|
|
95
92
|
WORDPRESS_DB_NAME: 'wordpress',
|
|
96
93
|
WORDPRESS_DEBUG: config.env?.WP_DEBUG || '0',
|
|
97
94
|
SERVER_NAME: config.hostname,
|
|
@@ -104,11 +101,11 @@ function generateWordPressService(config, wpVolumeName) {
|
|
|
104
101
|
|
|
105
102
|
// Add Shibboleth config if enabled
|
|
106
103
|
if (config.services.shibboleth) {
|
|
107
|
-
environment.SP_ENTITY_ID =
|
|
108
|
-
environment.IDP_ENTITY_ID =
|
|
109
|
-
environment.SHIB_IDP_LOGOUT =
|
|
110
|
-
environment.SHIB_SP_KEY =
|
|
111
|
-
environment.SHIB_SP_CERT =
|
|
104
|
+
environment.SP_ENTITY_ID = '${SP_ENTITY_ID:-}';
|
|
105
|
+
environment.IDP_ENTITY_ID = '${IDP_ENTITY_ID:-}';
|
|
106
|
+
environment.SHIB_IDP_LOGOUT = '${SHIB_IDP_LOGOUT:-}';
|
|
107
|
+
environment.SHIB_SP_KEY = '${SHIB_SP_KEY:-}';
|
|
108
|
+
environment.SHIB_SP_CERT = '${SHIB_SP_CERT:-}';
|
|
112
109
|
}
|
|
113
110
|
|
|
114
111
|
// Add S3 config if enabled
|
|
@@ -130,12 +127,12 @@ function generateWordPressService(config, wpVolumeName) {
|
|
|
130
127
|
wpConfigExtra += "define('SUBDOMAIN_INSTALL', false);\n";
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
if (config.services.s3proxy
|
|
134
|
-
wpConfigExtra +=
|
|
135
|
-
wpConfigExtra +=
|
|
136
|
-
wpConfigExtra +=
|
|
137
|
-
wpConfigExtra +=
|
|
138
|
-
wpConfigExtra +=
|
|
130
|
+
if (config.services.s3proxy) {
|
|
131
|
+
wpConfigExtra += "define('S3_UPLOADS_BUCKET', '${S3_UPLOADS_BUCKET}');\n";
|
|
132
|
+
wpConfigExtra += "define('S3_UPLOADS_REGION', '${S3_UPLOADS_REGION:-us-east-1}');\n";
|
|
133
|
+
wpConfigExtra += "define('S3_UPLOADS_KEY', '${S3_UPLOADS_ACCESS_KEY_ID}');\n";
|
|
134
|
+
wpConfigExtra += "define('S3_UPLOADS_SECRET', '${S3_UPLOADS_SECRET_ACCESS_KEY}');\n";
|
|
135
|
+
wpConfigExtra += "define('ACCESS_RULES_TABLE', '${S3_ACCESS_RULES_TABLE}');\n";
|
|
139
136
|
wpConfigExtra += "define('S3_UPLOADS_OBJECT_ACL', null);\n";
|
|
140
137
|
wpConfigExtra += "define('S3_UPLOADS_AUTOENABLE', true);\n";
|
|
141
138
|
wpConfigExtra += "define('S3_UPLOADS_DISABLE_REPLACE_UPLOAD_URL', true);\n";
|
|
@@ -183,14 +180,10 @@ function generateWordPressService(config, wpVolumeName) {
|
|
|
183
180
|
|
|
184
181
|
/**
|
|
185
182
|
* Generate S3 proxy service configuration
|
|
186
|
-
* @param {object}
|
|
183
|
+
* @param {object} _config - buwp-local configuration (unused - env vars used instead)
|
|
187
184
|
* @returns {object} S3 proxy service config
|
|
188
185
|
*/
|
|
189
|
-
function generateS3ProxyService(
|
|
190
|
-
const region = config.olap?.region || config.s3?.region || 'us-east-1';
|
|
191
|
-
const olapName = config.olap?.name || '';
|
|
192
|
-
const olapAcctNbr = config.olap?.accountNumber || '';
|
|
193
|
-
|
|
186
|
+
function generateS3ProxyService(_config) {
|
|
194
187
|
return {
|
|
195
188
|
image: 'public.ecr.aws/bostonuniversity-nonprod/aws-sigv4-proxy',
|
|
196
189
|
restart: 'always',
|
|
@@ -199,16 +192,16 @@ function generateS3ProxyService(config) {
|
|
|
199
192
|
'--name',
|
|
200
193
|
's3-object-lambda',
|
|
201
194
|
'--region',
|
|
202
|
-
|
|
195
|
+
'${OLAP_REGION:-us-east-1}',
|
|
203
196
|
'--no-verify-ssl',
|
|
204
197
|
'--host',
|
|
205
|
-
|
|
198
|
+
'${OLAP}-${OLAP_ACCT_NBR}.s3-object-lambda.${OLAP_REGION:-us-east-1}.amazonaws.com'
|
|
206
199
|
],
|
|
207
200
|
environment: {
|
|
208
201
|
healthcheck_path: '/s3proxy-healthcheck',
|
|
209
|
-
AWS_ACCESS_KEY_ID:
|
|
210
|
-
AWS_SECRET_ACCESS_KEY:
|
|
211
|
-
REGION:
|
|
202
|
+
AWS_ACCESS_KEY_ID: '${S3_UPLOADS_ACCESS_KEY_ID}',
|
|
203
|
+
AWS_SECRET_ACCESS_KEY: '${S3_UPLOADS_SECRET_ACCESS_KEY}',
|
|
204
|
+
REGION: '${S3_UPLOADS_REGION:-us-east-1}'
|
|
212
205
|
},
|
|
213
206
|
networks: ['wp-network']
|
|
214
207
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bostonuniversity/buwp-local",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Local WordPress development environment for Boston University projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
-
"buwp-local": "node bin/buwp-local.js",
|
|
12
|
+
"buwp-local": "node bin/buwp-local.js start",
|
|
13
13
|
"lint": "eslint ."
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## Plan: Environment-Based Credentials Migration (v0.4.1)
|
|
2
|
+
|
|
3
|
+
We've successfully shipped v0.4.0 with interactive init, sandbox support, configurable Docker images, and smart hostname defaults. The codebase is in excellent shape with real-world testing validated in both plugin and sandbox scenarios.
|
|
4
|
+
|
|
5
|
+
**Current Problem:** Credentials (database passwords, AWS keys, Shibboleth certs) are currently being read from the config/environment and then **written directly into the generated `docker-compose.yml`**. This means sensitive data sits in a generated file, which isn't ideal for security.
|
|
6
|
+
|
|
7
|
+
**Better Approach:** Use Docker Compose's native environment variable interpolation (`${VAR_NAME}`) so credentials stay in `.env.local` and never get written to the compose file.
|
|
8
|
+
|
|
9
|
+
### Steps
|
|
10
|
+
|
|
11
|
+
1. **Update `compose-generator.js` to use environment variable references**
|
|
12
|
+
- Database service: Change from `MYSQL_PASSWORD: dbPassword` to `MYSQL_PASSWORD: '${WORDPRESS_DB_PASSWORD:-password}'`
|
|
13
|
+
- WordPress service: Change from `WORDPRESS_DB_PASSWORD: config.db?.password` to `WORDPRESS_DB_PASSWORD: '${WORDPRESS_DB_PASSWORD:-password}'`
|
|
14
|
+
- S3 proxy service: Change from `AWS_ACCESS_KEY_ID: config.s3?.accessKeyId` to `AWS_ACCESS_KEY_ID: '${S3_UPLOADS_ACCESS_KEY_ID}'`
|
|
15
|
+
- WordPress `WORDPRESS_CONFIG_EXTRA`: Change from injecting actual S3 keys to using `${S3_UPLOADS_ACCESS_KEY_ID}` references
|
|
16
|
+
|
|
17
|
+
2. **Update `start.js` to pass `.env.local` to docker compose**
|
|
18
|
+
- Add `--env-file` flag to `docker compose up` command
|
|
19
|
+
- Ensure `.env.local` path is correctly resolved relative to project
|
|
20
|
+
|
|
21
|
+
3. **Update config loading to remove credential reading**
|
|
22
|
+
- Keep `extractEnvVars()` for backward compatibility but mark as deprecated
|
|
23
|
+
- Config validation no longer needs to check for credential presence in config object
|
|
24
|
+
- Document that credentials should only live in `.env.local`
|
|
25
|
+
|
|
26
|
+
4. **Update documentation**
|
|
27
|
+
- `USAGE.md` - Clarify that `.env.local` is the source of truth for credentials
|
|
28
|
+
- Add example showing compose file will have `${VAR}` references
|
|
29
|
+
- Security best practices section emphasizes this approach
|
|
30
|
+
|
|
31
|
+
5. **Test migration path**
|
|
32
|
+
- Verify existing projects with credentials in config still work (backward compat)
|
|
33
|
+
- Test new projects using only `.env.local`
|
|
34
|
+
- Verify generated compose file contains variable references, not actual values
|
|
35
|
+
- Ensure `docker compose` properly reads `.env.local`
|
|
36
|
+
|
|
37
|
+
### Further Considerations
|
|
38
|
+
|
|
39
|
+
1. **Backward compatibility**: Should we warn users if credentials exist in config? Or silently prefer `.env.local`?
|
|
40
|
+
2. **`.env.local` template**: Should we create `.env.local.example` during `init` command?
|
|
41
|
+
3. **Validation**: Should `config --validate` check that `.env.local` exists and has required variables?
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
**Why This Matters:**
|
|
46
|
+
- **Security**: Credentials never written to files, only referenced
|
|
47
|
+
- **Git safety**: Generated compose files are safe to accidentally commit (no secrets)
|
|
48
|
+
- **Best practices**: Aligns with Docker Compose's standard env var pattern
|
|
49
|
+
- **Simplicity**: Reduces complexity in config merging logic
|
|
50
|
+
|
|
51
|
+
**Effort Estimate:** Low-Medium (4-6 hours)
|
|
52
|
+
- Compose generation changes: ~2 hours
|
|
53
|
+
- Start command changes: ~1 hour
|
|
54
|
+
- Documentation: ~1 hour
|
|
55
|
+
- Testing: ~1-2 hours
|
|
56
|
+
|
|
57
|
+
**Ready to proceed?** This sets up a cleaner foundation before tackling Phase 2 features like keychain integration.
|