@bostonuniversity/buwp-local 0.7.4 → 0.7.6

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.
@@ -465,78 +465,16 @@ This architecture provides clean boundaries:
465
465
 
466
466
  | Concern | Location | Update Mechanism |
467
467
  |---------|----------|------------------|
468
- | WordPress core | Docker image | `buwp-local update` |
469
- | BU plugins | Docker image | `buwp-local update` |
470
- | BU theme | Docker image | `buwp-local update` |
468
+ | WordPress core | Docker image | `docker pull` |
469
+ | BU plugins | Docker image | `docker pull` |
470
+ | BU theme | Docker image | `docker pull` |
471
471
  | **Your plugin** | **Local filesystem** | **Your editor** |
472
472
  | **Your theme** | **Local filesystem** | **Your editor** |
473
- | Database | Docker volume (db_data) | Persists across updates |
474
- | **Uploads** | **S3 bucket** | **Via s3proxy** |
473
+ | Database | Docker volume | Persists across updates |
474
+ | Uploads | Docker volume | Persists across updates |
475
475
 
476
476
  Updates to WordPress never touch your development code. Updates to your code never require rebuilding WordPress.
477
477
 
478
- ### S3 Upload Architecture
479
-
480
- A critical design decision enables safe WordPress core updates: **all media uploads are stored in S3, not in the container filesystem**.
481
-
482
- ```
483
- WordPress Upload Flow:
484
- ┌──────────────┐
485
- │ User │ Uploads file via WP admin
486
- └──────┬───────┘
487
-
488
-
489
- ┌──────────────────────────────────┐
490
- │ WordPress Container │
491
- │ │
492
- │ BU S3 Uploads Plugin │
493
- │ (intercepts upload) │
494
- └──────┬───────────────────────────┘
495
-
496
-
497
- ┌──────────────────────────────────┐
498
- │ s3proxy Container │
499
- │ (AWS SigV4 authentication) │
500
- └──────┬───────────────────────────┘
501
-
502
-
503
- ┌──────────────────────────────────┐
504
- │ S3 Bucket │
505
- │ (permanent storage) │
506
- └──────────────────────────────────┘
507
- ```
508
-
509
- **Key Configuration** (from `compose-generator.js`):
510
-
511
- ```javascript
512
- if (config.services.s3proxy) {
513
- wpConfigExtra += "define('S3_UPLOADS_AUTOENABLE', true);\n";
514
- wpConfigExtra += "define('S3_UPLOADS_DISABLE_REPLACE_UPLOAD_URL', true);\n";
515
- }
516
- ```
517
-
518
- **What this means for updates:**
519
-
520
- The `wp_build` volume contains **zero user data**:
521
- - ✅ WordPress core files (disposable - from image)
522
- - ✅ BU plugins/themes (disposable - from image)
523
- - ❌ **No media uploads** (in S3 bucket)
524
- - ❌ **No database** (separate db_data volume)
525
- - ❌ **No custom code** (mapped from host filesystem)
526
-
527
- **Result:** The `wp_build` volume is purely infrastructure and can be safely wiped during updates to refresh WordPress core files.
528
-
529
- ```bash
530
- # This is safe because:
531
- # - Database preserved (db_data volume)
532
- # - Uploads preserved (S3 bucket)
533
- # - Your code preserved (local filesystem)
534
- npx buwp-local update # Wipes wp_build, recreates from image
535
- ```
536
-
537
- **Contrast with traditional WordPress:**
538
- In a standard WordPress installation, `wp-content/uploads/` contains irreplaceable user media files. In buwp-local, that directory is empty or contains only regenerable thumbnails/cache.
539
-
540
478
  For detailed migration guidance, see [MIGRATION_FROM_VM.md](MIGRATION_FROM_VM.md).
541
479
 
542
480
  ## Security Model
package/docs/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to buwp-local will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.6]
9
+
10
+ ### Fixed
11
+ - **`update` command now regenerates docker-compose.yml** - Config changes in `.buwp-local.json` are now applied during `update`, not just during `start`
12
+ - Ports, services, volume mappings, and other config changes now take effect when running `npx buwp-local update`
13
+ - Previously, config changes were silently ignored during update, requiring `stop` + `start` to apply
14
+
15
+ ### Changed
16
+ - `update` command now follows same pattern as `start` command for compose file generation
17
+ - Improved user feedback showing compose file regeneration step
18
+
19
+ ## [0.7.5]
20
+
21
+ ### Added
22
+ - Init template updated with `WP_ENVIRONMENT_TYPE=local` by default
23
+ - Provides standardized environment detection for plugins/themes
24
+
8
25
  ## [0.7.4]
9
26
 
10
27
  ### Changed
package/docs/COMMANDS.md CHANGED
@@ -141,6 +141,7 @@ npx buwp-local update --preserve-wpbuild
141
141
 
142
142
  **What it does:**
143
143
  - Checks if environment exists and Docker is running
144
+ - **Regenerates docker-compose.yml from current `.buwp-local.json` config** (applies config changes)
144
145
  - Pulls latest Docker images from registry
145
146
  - **Removes wp_build volume** to get fresh WordPress core files (unless `--preserve-wpbuild`)
146
147
  - Recreates containers with new images
@@ -93,6 +93,8 @@ sudo bash -c 'echo "127.0.0.1 username-myproject.local" >> /etc/hosts'
93
93
 
94
94
  Replace `username-myproject.local` with the hostname you chose in step 4.
95
95
 
96
+ The `init` command will also display this command for you to run.
97
+
96
98
  ### 6. Start Your Environment
97
99
 
98
100
  Start the Docker containers:
@@ -198,6 +198,9 @@ npx buwp-local start
198
198
  ```bash
199
199
  # Check Docker Desktop is running
200
200
  docker info
201
+
202
+ # Check port conflicts
203
+ npx buwp-local start --verbose
201
204
  ```
202
205
 
203
206
  ### Code changes not appearing
@@ -221,7 +224,7 @@ Check volume mappings in `.buwp-local.json`:
221
224
  # Verify Keychain entries
222
225
  npx buwp-local keychain list
223
226
 
224
- # Or use .env.local fallback --- this is a nice idea, but the actual command does not yet exist
227
+ # Or use .env.local fallback
225
228
  npx buwp-local keychain export > .env.local
226
229
  ```
227
230
 
package/docs/ROADMAP.md CHANGED
@@ -218,6 +218,25 @@ hostile.remove('127.0.0.1', config.hostname);
218
218
 
219
219
  **Breaking Change Note:** Existing projects will need `buwp-local update` or restart to apply new port bindings. Database access from phones/tablets/other computers will no longer work (rare use case).
220
220
 
221
+ ### Shipped in v0.7.5
222
+ - **Init Template updated with WP_ENVIRONMENT_TYPE** ✅
223
+ - New projects set `WP_ENVIRONMENT_TYPE=local` by default
224
+ - Provides standardized environment detection for plugins/themes
225
+ - Can be overridden to simulate staging/production if needed
226
+
227
+ ### Shipped in v0.7.6
228
+ - **Update Command Config Regeneration** ✅
229
+ - `update` command now regenerates docker-compose.yml from current `.buwp-local.json` config
230
+ - Config changes (ports, services, volume mappings, etc.) are now applied during `update`
231
+ - Fixes bug where config changes were silently ignored, requiring `stop` + `start` to apply
232
+ - Follows same pattern as `start` command for consistent behavior
233
+
234
+ **Problem:** User edited `.buwp-local.json` config (changed ports from 8080/8443 to 80/443), ran `npx buwp-local update`, but ports stayed at old values. Some settings updated (hostname) while others didn't, causing confusion.
235
+
236
+ **Root Cause:** Update command reused existing docker-compose.yml file instead of regenerating from current config like `start` command does.
237
+
238
+ **Solution:** Added compose file regeneration step to `update` command before pulling images. Now matches `start` command pattern and ensures config changes take effect.
239
+
221
240
  ### Potential Features
222
241
 
223
242
  - **Ability to add custom WORDPRESS_CONFIG_EXTRA environment variables**
@@ -227,6 +246,11 @@ hostile.remove('127.0.0.1', config.hostname);
227
246
  - Commands to export credentials to JSON file
228
247
  - Useful for migrating between machines or sharing setup
229
248
 
249
+ - **Command to generate a valid super-user**
250
+ - Consider adding a buwp-local command like `create-super-user` with a prompt that defaults to the current system username that can be used to create a valid WordPress super user tied to the current developer's BU account.
251
+ - This would be especially helpful for new users who are not familiar with WP CLI or need a quick way to get admin access without manually running WP CLI commands.
252
+ - One concern is that we don't want the primary command namespace to get too crowded with niche commands, perhaps we could have a "utils" command group for less commonly used commands like this, e.g. `buwp-local utils create-super-user`?
253
+
230
254
  - **Advanced Port Binding Configuration**
231
255
  - Optional config to override localhost-only binding for database/Redis
232
256
  - For advanced users who need network access to services
@@ -325,54 +349,6 @@ Will be informed by feedback from initial small group of users and actual pain p
325
349
  ### Quality
326
350
  - Standardized help for all CLI commands
327
351
 
328
- ### Code Structure
329
-
330
- #### Refactor credential handling to avoid duplication
331
- Suggested refactor:
332
- ```javascript
333
- // lib/docker-helpers.js (new file)
334
- export function prepareDockerComposeEnv(projectPath, projectName) {
335
- const credentials = loadKeychainCredentials();
336
- let tempEnvPath = null;
337
-
338
- if (Object.keys(credentials).length > 0) {
339
- try {
340
- tempEnvPath = createSecureTempEnvFile(credentials, projectName);
341
- } catch (err) {
342
- console.warn(chalk.yellow(`⚠️ Could not load keychain credentials: ${err.message}`));
343
- }
344
- }
345
-
346
- const envFilePath = path.join(projectPath, ENV_FILE_NAME);
347
- const envFileFlag = fs.existsSync(envFilePath) ? `--env-file ${envFilePath}` : '';
348
- const tempEnvFileFlag = tempEnvPath ? `--env-file ${tempEnvPath}` : '';
349
-
350
- return {
351
- flags: `${tempEnvFileFlag} ${envFileFlag}`.trim(),
352
- tempEnvPath,
353
- cleanup: () => tempEnvPath && secureDeleteTempEnvFile(tempEnvPath)
354
- };
355
- }
356
- ```
357
-
358
- #### Centralize volume naming logic
359
-
360
- Suggested refactor:
361
- ```javascript
362
- // lib/volume-naming.js (new file)
363
- export function getVolumeNames(projectName) {
364
- return {
365
- db: `${projectName}_db_data`,
366
- wp: `${projectName}_wp_build`
367
- };
368
- }
369
-
370
- // Or simpler - just add to config.js
371
- export function getWpVolumeName(projectName) {
372
- return `${projectName}_wp_build`;
373
- }
374
- ```
375
-
376
352
  ---
377
353
 
378
354
  ## Decision Framework
@@ -262,6 +262,7 @@ async function initCommand(options) {
262
262
  mappings: [],
263
263
  env: {
264
264
  WP_DEBUG: true,
265
+ WP_ENVIRONMENT_TYPE: 'local',
265
266
  XDEBUG: answers.xdebug || false
266
267
  }
267
268
  };
@@ -7,17 +7,17 @@ import { execSync } from 'child_process';
7
7
  import path from 'path';
8
8
  import fs from 'fs';
9
9
  import { loadConfig, loadKeychainCredentials, createSecureTempEnvFile, secureDeleteTempEnvFile, ENV_FILE_NAME } from '../config.js';
10
+ import { generateComposeFile } from '../compose-generator.js';
10
11
 
11
12
  async function updateCommand(options = {}) {
12
13
  console.log(chalk.blue('🔄 Updating Docker images...\n'));
13
14
 
14
15
  try {
15
16
  const projectPath = process.cwd();
16
- const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
17
- const composeDir = path.dirname(composePath);
18
17
  const envFilePath = path.join(projectPath, ENV_FILE_NAME);
18
+ const composePath = path.join(projectPath, '.buwp-local', 'docker-compose.yml');
19
19
 
20
- // Check if docker-compose.yml exists
20
+ // Check if docker-compose.yml exists (indicates environment was previously started)
21
21
  if (!fs.existsSync(composePath)) {
22
22
  console.log(chalk.yellow('⚠️ No environment found.'));
23
23
  console.log(chalk.gray('Run "buwp-local start" to create an environment.\n'));
@@ -28,6 +28,14 @@ async function updateCommand(options = {}) {
28
28
  const config = loadConfig(projectPath);
29
29
  const projectName = config.projectName || 'buwp-local';
30
30
 
31
+ // Regenerate docker-compose.yml from current config
32
+ // This ensures any config changes are applied during update
33
+ console.log(chalk.gray('Regenerating docker-compose.yml from current config...'));
34
+ const newComposePath = generateComposeFile(config, projectPath);
35
+ console.log(chalk.green(`✓ Generated ${newComposePath}\n`));
36
+
37
+ const composeDir = path.dirname(composePath);
38
+
31
39
  // Check if Docker is running
32
40
  try {
33
41
  execSync('docker info', { stdio: 'ignore' });
package/lib/config.js CHANGED
@@ -228,6 +228,7 @@ function initConfig(projectPath = process.cwd(), options = {}) {
228
228
  mappings: [],
229
229
  env: {
230
230
  WP_DEBUG: true,
231
+ WP_ENVIRONMENT_TYPE: 'local',
231
232
  XDEBUG: false
232
233
  }
233
234
  };
package/lib/index.js CHANGED
@@ -15,17 +15,3 @@ export const generateComposeFile = composeGenerator.generateComposeFile;
15
15
  export const CONFIG_FILE_NAME = config.CONFIG_FILE_NAME;
16
16
  export const ENV_FILE_NAME = config.ENV_FILE_NAME;
17
17
  export const DEFAULT_CONFIG = config.DEFAULT_CONFIG;
18
-
19
- // Keychain exports
20
- export const setCredential = keychain.setCredential;
21
- export const getCredential = keychain.getCredential;
22
- export const hasCredential = keychain.hasCredential;
23
- export const listCredentials = keychain.listCredentials;
24
- export const clearAllCredentials = keychain.clearAllCredentials;
25
- export const isPlatformSupported = keychain.isPlatformSupported;
26
- export const isMultilineCredential = keychain.isMultilineCredential;
27
- export const parseCredentialsFile = keychain.parseCredentialsFile;
28
- export const CREDENTIAL_KEYS = keychain.CREDENTIAL_KEYS;
29
- export const CREDENTIAL_GROUPS = keychain.CREDENTIAL_GROUPS;
30
- export const CREDENTIAL_DESCRIPTIONS = keychain.CREDENTIAL_DESCRIPTIONS;
31
- export const MULTILINE_CREDENTIALS = keychain.MULTILINE_CREDENTIALS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bostonuniversity/buwp-local",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "description": "Local WordPress development environment for Boston University projects",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
package/readme.md CHANGED
@@ -113,3 +113,4 @@ Your local WordPress site should now be accessible at the hostname you configure
113
113
  - ✅ Smart initialization for plugins, themes, and mu-plugins
114
114
  - ✅ Volume mapping for live code sync
115
115
  - ✅ Xdebug support for step debugging
116
+ - ✅ WordPress environment detection (`WP_ENVIRONMENT_TYPE` set to `local`)
@@ -1,27 +0,0 @@
1
- {
2
- "image": "ghcr.io/bu-ist/bu-wp-docker-mod_shib:arm64-latest",
3
- "hostname": "wordpress.local",
4
- "multisite": true,
5
- "services": {
6
- "redis": true,
7
- "s3proxy": true,
8
- "shibboleth": true
9
- },
10
- "ports": {
11
- "http": 80,
12
- "https": 443,
13
- "db": 3306,
14
- "redis": 6379
15
- },
16
- "mappings": [
17
- {
18
- "local": "./",
19
- "container": "/var/www/html/wp-content/plugins/my-plugin",
20
- "comment": "Map current directory to a plugin location"
21
- }
22
- ],
23
- "env": {
24
- "WP_DEBUG": true,
25
- "XDEBUG": false
26
- }
27
- }
@@ -1,26 +0,0 @@
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
@@ -1,240 +0,0 @@
1
- # v0.5.0 Phase 3: Hybrid Secure Temp File Integration
2
-
3
- ## Overview
4
- Completed implementation of credential loading from macOS keychain into Docker Compose via secure temporary environment files. This is the final integration step of v0.5.0 keychain feature.
5
-
6
- ## What Was Implemented
7
-
8
- ### 1. **Credential Loading Functions** (`lib/config.js`)
9
-
10
- Added three new exported functions:
11
-
12
- #### `loadKeychainCredentials()`
13
- - Retrieves all 15 stored credentials from macOS keychain
14
- - Returns empty object on non-macOS platforms (graceful degradation)
15
- - Checks `isPlatformSupported()` before attempting keychain access
16
- - Iterates through `CREDENTIAL_KEYS` constant to load each credential
17
-
18
- #### `createSecureTempEnvFile(credentials, projectName)`
19
- - Creates `/tmp/.buwp-local-{projectName}-{timestamp}.env` file
20
- - Uses atomic file creation with exclusive write flag (`'wx'`)
21
- - Sets restrictive permissions to user read/write only (`0o600`)
22
- - Properly escapes multiline credentials:
23
- - Backslashes: `\\` → `\\\\\\\\`
24
- - Double quotes: `"` → `\"`
25
- - Newlines: `\n` → `\\n`
26
- - Ensures shell interpretation works correctly for complex values (SHIB_SP_KEY, SHIB_SP_CERT)
27
- - Returns path to created temp file
28
-
29
- #### `secureDeleteTempEnvFile(filePath)`
30
- - Overwrites file content with zeros before deletion (defense against forensic recovery)
31
- - Unlinks file after secure overwrite
32
- - Returns boolean success status
33
- - Non-fatal errors - logs warnings but doesn't throw (temp files are ephemeral)
34
-
35
- ### 2. **Start Command Integration** (`lib/commands/start.js`)
36
-
37
- Updated `startCommand()` function to:
38
-
39
- 1. **Import new functions** from config.js
40
- 2. **Load keychain credentials** after generating compose file:
41
- ```javascript
42
- const keychainCredentials = loadKeychainCredentials();
43
- const keychainCredCount = Object.keys(keychainCredentials).length;
44
- ```
45
-
46
- 3. **Create secure temp file** if credentials available:
47
- ```javascript
48
- if (keychainCredCount > 0) {
49
- tempEnvPath = createSecureTempEnvFile(keychainCredentials, projectName);
50
- }
51
- ```
52
-
53
- 4. **Layer environment files** in Docker Compose command:
54
- ```bash
55
- docker compose -p {projectName} --env-file {tempEnvFile} --env-file {.env.local} -f {composePath} up -d
56
- ```
57
-
58
- 5. **Ensure cleanup** with try/finally block:
59
- - Cleanup happens even if Docker Compose fails
60
- - Temp file securely deleted after containers start
61
-
62
- ### 3. **Credential Precedence**
63
-
64
- Docker Compose loads env files left-to-right with later files overriding earlier ones:
65
-
66
- ```
67
- Keychain Credentials (--env-file /tmp/.buwp-local-*.env)
68
- ↓ [overridden by]
69
- .env.local Project Overrides (--env-file .env.local)
70
- ↓ [overridden by]
71
- docker-compose.yml Environment Defaults
72
- ```
73
-
74
- **Precedence Order (highest to lowest):**
75
- 1. `.env.local` - Project-specific credential overrides
76
- 2. Keychain - Global default credentials (all 15 keys)
77
- 3. docker-compose.yml - Hardcoded defaults
78
-
79
- ## Security Architecture
80
-
81
- ### Threat Model: Process List Visibility
82
- **Original concern:** Won't credentials be visible in `ps auxe`?
83
-
84
- **Answer:** No. With this approach:
85
- - Docker command shows: `docker compose --env-file /tmp/.buwp-local-test-project-1234567890.env ...`
86
- - Credentials are in the file, NOT in the process command line
87
- - Process list shows only the file path (which is harmless)
88
-
89
- ### Threat Model: Filesystem Exposure
90
- **Risk:** Brief window where unencrypted credentials are on disk
91
-
92
- **Mitigations:**
93
- 1. **Atomic creation** - File created exclusively with perms set atomically (no TOCTOU window)
94
- 2. **Restrictive permissions** - `0o600` (user read/write only, no group/others access)
95
- 3. **Ephemeral location** - `/tmp` directory (typically in-memory on modern systems, auto-cleaned)
96
- 4. **Secure deletion** - Overwrite with zeros before unlinking (prevents forensic recovery)
97
- 5. **Short lifetime** - File exists only during `docker compose up` command (~1-2 seconds)
98
- 6. **Guaranteed cleanup** - try/finally ensures deletion even if Docker fails
99
-
100
- ### Why Not Process Environment Variables?
101
- - **Worse security:** All env vars visible in `ps auxe` output to any user on system
102
- - **Less stable:** Large multiline values (40+ lines) cause issues
103
- - **Less standard:** Breaks Docker Compose file-based patterns
104
-
105
- ### Why Not Store Credentials in .env.local?
106
- - **Already doing this** - `.env.local` is still supported and takes precedence
107
- - **One-time setup** - Keychain eliminates need to copy credentials to every project
108
- - **Secure storage** - Keychain uses macOS Secure Enclave on newer Macs
109
-
110
- ## Integration Flow
111
-
112
- ```
113
- 1. Start command runs
114
-
115
- 2. Load config from .buwp-local.json
116
-
117
- 3. Load keychain credentials (15 total)
118
-
119
- 4. Create temp env file (/tmp/.buwp-local-{project}-{timestamp}.env)
120
- - Atomic creation with 0o600 permissions
121
- - Properly escaped multiline values
122
-
123
- 5. Build Docker Compose command with layered env files
124
- - --env-file /tmp/.buwp-local-{project}-{timestamp}.env
125
- - --env-file .env.local (if exists)
126
-
127
- 6. Execute Docker Compose up
128
-
129
- 7. Clean up temp file (try/finally)
130
- - Overwrite with zeros
131
- - Unlink
132
-
133
- 8. Success message + usage tips
134
- ```
135
-
136
- ## Credentials Loaded
137
-
138
- All 15 credentials from keychain are available:
139
-
140
- **Database (2):**
141
- - WORDPRESS_DB_PASSWORD
142
- - DB_ROOT_PASSWORD
143
-
144
- **Shibboleth (5):**
145
- - SP_ENTITY_ID
146
- - IDP_ENTITY_ID
147
- - SHIB_IDP_LOGOUT
148
- - SHIB_SP_KEY (40+ lines)
149
- - SHIB_SP_CERT (24+ lines)
150
-
151
- **S3 (5):**
152
- - S3_UPLOADS_BUCKET
153
- - S3_UPLOADS_REGION
154
- - S3_UPLOADS_ACCESS_KEY_ID
155
- - S3_UPLOADS_SECRET_ACCESS_KEY
156
- - S3_ACCESS_RULES_TABLE
157
-
158
- **OLAP (3):**
159
- - OLAP
160
- - OLAP_ACCT_NBR
161
- - OLAP_REGION
162
-
163
- ## Testing Results
164
-
165
- Automated integration test verification:
166
-
167
- ✓ Load 15 credentials from keychain
168
- ✓ Create secure temp env file with 0o600 permissions
169
- ✓ Format env file with proper KEY="VALUE" quoting
170
- ✓ Handle multiline value escaping correctly
171
- ✓ Overwrite file with zeros before deletion
172
- ✓ Securely delete temp file
173
-
174
- All tests passed successfully.
175
-
176
- ## Version Update
177
-
178
- Updated package.json version:
179
- - Previous: v0.4.1
180
- - Current: v0.5.0
181
-
182
- ## Code Quality
183
-
184
- All code passes ESLint checks with no errors or warnings.
185
-
186
- ## Next Steps
187
-
188
- Possible future enhancements (not in v0.5.0 scope):
189
-
190
- 1. **Phase 4: Init Command Enhancements**
191
- - Auto-populate `buwp-local setup --file` from existing `.env` files
192
- - Suggest keychain import during `init` command
193
-
194
- 2. **Phase 5: Global Registry**
195
- - `~/.buwp-local/registry.json` tracking which projects have credentials
196
- - Dashboard showing all stored credentials across projects
197
-
198
- 3. **Phase 6: Cross-Platform Support**
199
- - Windows DPAPI support (via `credential` PowerShell module)
200
- - Linux pass/secretservice support
201
- - Fallback to encrypted `.buwp-local/.env.encrypted` files
202
-
203
- ## Architecture Summary
204
-
205
- **Hybrid Secure Temp File Approach:**
206
- - **Security:** Process list hidden + filesystem defenses
207
- - **Stability:** Aligns with Docker Compose standard patterns
208
- - **Usability:** Intuitive file-based precedence and override mechanism
209
- - **Compatibility:** Maintains existing `.env.local` behavior
210
-
211
- **Key Decision Rationale:**
212
- Process list visibility is worse attack vector than brief filesystem window with defense-in-depth mitigations (atomic creation, 600 perms, /tmp location, overwrite-before-delete).
213
-
214
- ## Files Modified
215
-
216
- 1. `lib/config.js` (+80 lines)
217
- - Added keychain import
218
- - Added 3 new exported functions
219
- - No breaking changes to existing exports
220
-
221
- 2. `lib/commands/start.js` (+25 lines)
222
- - Updated imports to include 3 new functions
223
- - Added credential loading logic
224
- - Added temp file creation and cleanup
225
- - No breaking changes to command interface
226
-
227
- 3. `package.json`
228
- - Updated version to 0.5.0
229
-
230
- ## Status Summary
231
-
232
- **v0.5.0 Completion Status:**
233
- - ✅ Phase 1: Keychain core module (v0.5.0)
234
- - ✅ Phase 2: JSON bulk import (v0.5.0)
235
- - ✅ Phase 3: Hybrid secure temp file integration (v0.5.0) ← COMPLETED THIS SESSION
236
- - ⏭️ Phase 4: Init command enhancements (v0.6.0)
237
- - ⏭️ Phase 5: Global registry (v0.7.0)
238
- - ⏭️ Phase 6: Cross-platform support (v1.0.0+)
239
-
240
- **v0.5.0 is now feature-complete and ready for testing.**
@@ -1,385 +0,0 @@
1
- # Implementation Summary - Multi-Project Support
2
-
3
- ## What We Built
4
-
5
- Successfully implemented **three major features** requested from real-world usage feedback:
6
-
7
- ### 1. ✅ Unique Docker Compose Project Names
8
- **Problem Solved:** Multiple repos using buwp-local would conflict in Docker Desktop and overwrite each other.
9
-
10
- **Solution Implemented:**
11
- - Auto-generate project name from directory name
12
- - Pass `-p {projectName}` flag to all docker-compose commands
13
- - Projects now show separately in Docker Desktop
14
- - Multiple instances can run simultaneously
15
-
16
- **Technical Changes:**
17
- - Added `projectName` field to config (defaults to directory basename)
18
- - Added `getProjectName()` and `sanitizeProjectName()` functions in `config.js`
19
- - Updated `start.js`, `stop.js`, `destroy.js`, `logs.js` to use `-p` flag
20
-
21
- ### 2. ✅ Isolated Volumes Per Project
22
- **Problem Solved:** All projects shared the same database and WordPress volumes, causing conflicts.
23
-
24
- **Solution Implemented:**
25
- - Volume names prefixed with project name: `{projectName}_db_data`, `{projectName}_wp_build`
26
- - Each project gets completely isolated storage
27
- - No cross-contamination between projects
28
-
29
- **Technical Changes:**
30
- - Modified `generateComposeConfig()` to create project-specific volume names
31
- - Updated `generateDbService()` to accept `dbVolumeName` parameter
32
- - Updated `generateWordPressService()` to accept `wpVolumeName` parameter
33
- - Volume names dynamically generated based on `config.projectName`
34
-
35
- ### 3. ✅ Smart Configuration Initialization
36
- **Problem Solved:** Users had to manually figure out and type correct container paths for plugins/themes/mu-plugins.
37
-
38
- **Solution Implemented:**
39
- - New CLI flags: `--plugin`, `--mu-plugin`, `--theme`
40
- - Auto-detects directory name
41
- - Auto-generates correct mapping path
42
- - Sets sensible defaults (project name, hostname)
43
-
44
- **Technical Changes:**
45
- - Modified `initConfig()` to accept `options` parameter with plugin/muPlugin/theme flags
46
- - Updated config command to pass initialization type to `initConfig()`
47
- - Added CLI options in `bin/buwp-local.js` for `--plugin`, `--mu-plugin`, `--theme`
48
- - Auto-generates hostname as `{projectName}.local`
49
-
50
- ---
51
-
52
- ## Files Modified
53
-
54
- ### Core Library Files
55
- 1. **`lib/config.js`**
56
- - Added `projectName` to DEFAULT_CONFIG
57
- - Added project name auto-detection in `loadConfig()`
58
- - Added `getProjectName()` function
59
- - Added `sanitizeProjectName()` function
60
- - Modified `initConfig()` to support smart initialization options
61
- - Auto-generates project-specific mappings based on type
62
-
63
- 2. **`lib/compose-generator.js`**
64
- - Modified `generateComposeConfig()` to use project-specific volume names
65
- - Updated `generateDbService()` with `dbVolumeName` parameter
66
- - Updated `generateWordPressService()` with `wpVolumeName` parameter
67
- - Dynamic volume naming: `{projectName}_db_data` and `{projectName}_wp_build`
68
-
69
- ### Command Files
70
- 3. **`lib/commands/start.js`**
71
- - Added project name to docker-compose command: `-p ${projectName}`
72
- - Display project name in success message
73
-
74
- 4. **`lib/commands/stop.js`**
75
- - Import `loadConfig` to get project name
76
- - Added `-p ${projectName}` flag to docker-compose command
77
-
78
- 5. **`lib/commands/destroy.js`**
79
- - Import `loadConfig` to get project name
80
- - Added `-p ${projectName}` flag to docker-compose command
81
- - Show project name in confirmation prompt
82
-
83
- 6. **`lib/commands/logs.js`**
84
- - Import `loadConfig` to get project name
85
- - Added `-p ${projectName}` flag to docker-compose command
86
-
87
- 7. **`lib/commands/config.js`**
88
- - Added logic to handle `--plugin`, `--mu-plugin`, `--theme` flags
89
- - Pass initialization options to `initConfig()`
90
- - Display appropriate messages for each initialization type
91
- - Updated help text with new flags
92
-
93
- ### CLI Entry Point
94
- 8. **`bin/buwp-local.js`**
95
- - Added `--plugin`, `--mu-plugin`, `--theme` options to config command
96
- - Updated command descriptions
97
-
98
- ---
99
-
100
- ## Testing Results
101
-
102
- ### ✅ Smart Initialization Tested
103
- ```bash
104
- # Plugin
105
- cd /tmp/test-plugin
106
- buwp-local config --init --plugin
107
- # ✓ Created: ./var/www/html/wp-content/plugins/test-plugin mapping
108
-
109
- # Theme
110
- cd /tmp/my-custom-theme
111
- buwp-local config --init --theme
112
- # ✓ Created: ./var/www/html/wp-content/themes/my-custom-theme mapping
113
-
114
- # MU-Plugin
115
- cd /tmp/bu-navigation
116
- buwp-local config --init --mu-plugin
117
- # ✓ Created: ./var/www/html/wp-content/mu-plugins/bu-navigation mapping
118
- ```
119
-
120
- ### ✅ Project Name Auto-Detection Tested
121
- - Directory name correctly extracted
122
- - Project name properly sanitized
123
- - Hostname auto-generated from project name
124
- - Config display shows project name
125
-
126
- ### ✅ Volume Isolation Verified
127
- - Generated compose files show unique volume names
128
- - Volume names include project identifier
129
- - No conflicts between projects
130
-
131
- ---
132
-
133
- ## Configuration Schema Changes
134
-
135
- ### New Field: `projectName`
136
-
137
- ```json
138
- {
139
- "projectName": "my-plugin-name", // NEW - auto-generated from directory
140
- "image": "ghcr.io/bu-ist/bu-wp-docker-mod_shib:arm64-latest",
141
- "hostname": "my-plugin-name.local", // Auto-generated from projectName
142
- "multisite": true,
143
- // ... rest of config
144
- }
145
- ```
146
-
147
- ### Smart Mapping Examples
148
-
149
- **Plugin Init:**
150
- ```json
151
- {
152
- "projectName": "bu-custom-analytics",
153
- "hostname": "bu-custom-analytics.local",
154
- "mappings": [
155
- {
156
- "local": "./",
157
- "container": "/var/www/html/wp-content/plugins/bu-custom-analytics"
158
- }
159
- ]
160
- }
161
- ```
162
-
163
- **Theme Init:**
164
- ```json
165
- {
166
- "projectName": "responsive-framework",
167
- "hostname": "responsive-framework.local",
168
- "mappings": [
169
- {
170
- "local": "./",
171
- "container": "/var/www/html/wp-content/themes/responsive-framework"
172
- }
173
- ]
174
- }
175
- ```
176
-
177
- **MU-Plugin Init:**
178
- ```json
179
- {
180
- "projectName": "bu-navigation",
181
- "hostname": "bu-navigation.local",
182
- "mappings": [
183
- {
184
- "local": "./",
185
- "container": "/var/www/html/wp-content/mu-plugins/bu-navigation"
186
- }
187
- ]
188
- }
189
- ```
190
-
191
- ---
192
-
193
- ## Usage Examples
194
-
195
- ### Single Project (Original Workflow)
196
- ```bash
197
- cd ~/projects/my-plugin
198
- buwp-local config --init --plugin
199
- # Edit .env.local with credentials
200
- buwp-local start
201
- # Access at http://my-plugin.local
202
- ```
203
-
204
- ### Multiple Projects (New Capability)
205
- ```bash
206
- # Project A - Plugin
207
- cd ~/projects/bu-custom-analytics
208
- buwp-local config --init --plugin
209
- buwp-local start # Runs on port 80
210
-
211
- # Project B - Another Plugin (different ports)
212
- cd ~/projects/bu-slideshow
213
- buwp-local config --init --plugin
214
- # Edit .buwp-local.json - change ports to 8081/8444/3308/6381
215
- buwp-local start # Runs on port 8081
216
-
217
- # Project C - Theme
218
- cd ~/projects/responsive-framework
219
- buwp-local config --init --theme
220
- # Edit .buwp-local.json - change ports to 8082/8445/3309/6382
221
- buwp-local start # Runs on port 8082
222
-
223
- # All three running simultaneously with separate databases!
224
- ```
225
-
226
- ### Docker Desktop View
227
- ```
228
- Projects:
229
- ├─ bu-custom-analytics
230
- ├─ bu-slideshow
231
- └─ responsive-framework
232
-
233
- Volumes:
234
- ├─ bu-custom-analytics_db_data
235
- ├─ bu-custom-analytics_wp_build
236
- ├─ bu-slideshow_db_data
237
- ├─ bu-slideshow_wp_build
238
- ├─ responsive-framework_db_data
239
- └─ responsive-framework_wp_build
240
- ```
241
-
242
- ---
243
-
244
- ## Benefits Delivered
245
-
246
- ### For Individual Developers
247
- - ✅ Work on multiple projects simultaneously
248
- - ✅ Each project has isolated database
249
- - ✅ Fast setup with smart init flags
250
- - ✅ No manual path configuration needed
251
- - ✅ Clear project organization in Docker Desktop
252
-
253
- ### For Teams
254
- - ✅ Standardized setup process
255
- - ✅ Less room for configuration errors
256
- - ✅ Easy onboarding with simple commands
257
- - ✅ Scalable to 20+ developers
258
- - ✅ Each developer can run multiple projects
259
-
260
- ### For Project Management
261
- - ✅ Easy to see which projects are running
262
- - ✅ No accidental database overwrites
263
- - ✅ Clear volume organization
264
- - ✅ Predictable naming conventions
265
-
266
- ---
267
-
268
- ## Backwards Compatibility
269
-
270
- ### Migration Path
271
- Existing projects without `projectName` will:
272
- 1. Auto-generate project name from directory
273
- 2. Create new volumes with project-specific names
274
- 3. Need to run `destroy` then `start` to migrate
275
-
276
- ### Recommendation for Existing Users
277
- ```bash
278
- # In each existing project:
279
- buwp-local destroy -f # Removes old shared volumes
280
- buwp-local start # Creates new isolated volumes
281
- ```
282
-
283
- ---
284
-
285
- ## Documentation Created
286
-
287
- ### New Documents
288
- 1. **`MULTI_PROJECT_GUIDE.md`** - Comprehensive guide for multi-project workflows
289
- - Feature explanations
290
- - Usage examples
291
- - Troubleshooting
292
- - Best practices
293
- - Migration guide
294
-
295
- ### Updated Documents
296
- - Configuration examples now include `projectName`
297
- - CLI help text shows new flags
298
- - Command descriptions updated
299
-
300
- ---
301
-
302
- ## Next Steps & Future Enhancements
303
-
304
- ### Immediate (Ready to Use)
305
- - ✅ All features tested and working
306
- - ✅ Documentation complete
307
- - ✅ Ready for team rollout
308
-
309
- ### Phase 2 Suggestions (Based on Usage)
310
- 1. **Project Listing Command**
311
- ```bash
312
- buwp-local list # Show all active buwp-local projects
313
- ```
314
-
315
- 2. **Port Auto-Assignment**
316
- - Automatically find available ports
317
- - Suggest ports in `config --init`
318
-
319
- 3. **Preset Configurations**
320
- ```bash
321
- buwp-local config --init --plugin --preset bu-standard
322
- # Loads common settings for BU projects
323
- ```
324
-
325
- 4. **Project Templates**
326
- ```bash
327
- buwp-local config --init --template bu-plugin
328
- # Includes common dependencies, settings, etc.
329
- ```
330
-
331
- 5. **Health Status Command**
332
- ```bash
333
- buwp-local status
334
- # Shows status of current project
335
- # - Running containers
336
- # - Port mappings
337
- # - Volume sizes
338
- # - WordPress version
339
- ```
340
-
341
- ---
342
-
343
- ## Technical Achievements
344
-
345
- ### Clean Implementation
346
- - ✅ Minimal changes to existing code
347
- - ✅ Backwards compatible (with migration)
348
- - ✅ Consistent naming conventions
349
- - ✅ Clear function parameters
350
- - ✅ Comprehensive error handling
351
-
352
- ### Code Quality
353
- - ✅ JSDoc comments maintained
354
- - ✅ Functions remain single-responsibility
355
- - ✅ No breaking changes to public API
356
- - ✅ Easy to test and debug
357
-
358
- ### User Experience
359
- - ✅ Intuitive flag names
360
- - ✅ Helpful feedback messages
361
- - ✅ Clear error messages
362
- - ✅ Sensible defaults
363
- - ✅ No required manual configuration
364
-
365
- ---
366
-
367
- ## Summary
368
-
369
- **All three requested features successfully implemented:**
370
- 1. ✅ Unique project names for Docker Desktop identification
371
- 2. ✅ Isolated volumes per project for data separation
372
- 3. ✅ Smart config init with auto-mapping
373
-
374
- **Testing confirms:**
375
- - Multiple projects run simultaneously ✅
376
- - Projects remain isolated ✅
377
- - Smart initialization works correctly ✅
378
- - All commands use project names properly ✅
379
-
380
- **Ready for:**
381
- - ✅ Team rollout
382
- - ✅ Real-world usage
383
- - ✅ Multi-project workflows
384
-
385
- The tool now fully supports the enterprise multi-project development workflow needed for a team of 20+ developers!
@@ -1,140 +0,0 @@
1
- # Keychain Integration - Implementation Summary
2
-
3
- ## Overview
4
-
5
- Successfully implemented macOS Keychain integration for secure credential storage in buwp-local v0.5.0. This allows users to store credentials once and have them automatically available across all projects.
6
-
7
- ## Files Created
8
-
9
- ### 1. `lib/keychain.js` - Core Keychain Module
10
- **Functions:**
11
- - `setCredential(key, value)` - Store credential in keychain
12
- - `getCredential(key)` - Retrieve credential from keychain
13
- - `hasCredential(key)` - Check if credential exists
14
- - `deleteCredential(key)` - Remove credential
15
- - `listCredentials()` - Get all stored credential keys
16
- - `clearAllCredentials()` - Remove all buwp-local credentials
17
- - `isPlatformSupported()` - Check for macOS platform
18
-
19
- **Constants:**
20
- - `CREDENTIAL_KEYS` - All 15 credential keys
21
- - `CREDENTIAL_GROUPS` - Organized by category (database, shibboleth, s3, olap)
22
- - `CREDENTIAL_DESCRIPTIONS` - Human-readable descriptions for prompts
23
-
24
- **Implementation Details:**
25
- - Uses macOS `security` command via `execSync`
26
- - Service name: `buwp-local`
27
- - Uses `-U` flag to update existing credentials instead of duplicating
28
- - Graceful error handling with user-friendly messages
29
-
30
- ### 2. `lib/commands/keychain.js` - CLI Command Handler
31
- **Subcommands:**
32
- - `setup` - Interactive setup for all credentials
33
- - `set <key> [value]` - Set individual credential
34
- - `get <key>` - Retrieve credential (masked display)
35
- - `list` - Show all stored credentials by group
36
- - `clear` - Remove all credentials (with confirmation)
37
- - `status` - Show platform support and credential status
38
-
39
- **Features:**
40
- - Interactive prompts using `prompts` package
41
- - Grouped credential display (database, shibboleth, s3, olap)
42
- - Existing credential detection with overwrite warnings
43
- - Force flag support for automation
44
- - macOS keychain access warning at start of setup
45
-
46
- ## Files Modified
47
-
48
- ### 3. `bin/buwp-local.js`
49
- - Added import for `keychainCommand`
50
- - Registered `keychain` command with subcommands
51
- - Added `-f, --force` option support
52
-
53
- ### 4. `lib/index.js`
54
- - Exported all keychain functions
55
- - Exported credential schema constants
56
-
57
- ## Usage Examples
58
-
59
- ### First-Time Setup
60
- ```bash
61
- # Interactive setup (all credentials)
62
- buwp-local keychain setup
63
-
64
- # Set individual credential
65
- buwp-local keychain set WORDPRESS_DB_PASSWORD mypassword
66
-
67
- # Check status
68
- buwp-local keychain status
69
- ```
70
-
71
- ### Managing Credentials
72
- ```bash
73
- # List stored credentials
74
- buwp-local keychain list
75
-
76
- # Get credential value (masked)
77
- buwp-local keychain get WORDPRESS_DB_PASSWORD
78
-
79
- # Clear all credentials
80
- buwp-local keychain clear
81
- # Or skip confirmation:
82
- buwp-local keychain clear --force
83
- ```
84
-
85
- ## Testing Results
86
-
87
- ✅ All functions tested and working:
88
- - Platform detection (macOS supported ✓)
89
- - Set credential via command line
90
- - Get credential with masking (test*****word)
91
- - List credentials by group
92
- - Clear all credentials
93
- - Linting passes cleanly
94
-
95
- ## User Experience
96
-
97
- ### Warnings & Messages
98
- - **Platform check**: Non-macOS users see clear message about .env.local fallback
99
- - **Keychain access**: Users warned about macOS permission prompt before setup
100
- - **Overwrite protection**: Warns when overwriting existing credentials
101
- - **Grouped display**: Credentials organized by functional category
102
-
103
- ### Security Features
104
- - Credentials never displayed in full (masked in `get` command)
105
- - Stored securely in macOS keychain (encrypted by OS)
106
- - Individual credential deletion supported
107
- - Bulk clear with confirmation (unless --force)
108
-
109
- ## Design Decisions
110
-
111
- 1. **Full credential set required** - `setup` prompts for all 15 credentials to ensure complete stack functionality
112
- 2. **Warning before overwrite** - Users must confirm when updating existing credentials (unless --force)
113
- 3. **Sparse error messages** - Simple, clear error reporting without over-engineering
114
- 4. **macOS-only for now** - Platform detection with graceful fallback to .env.local on other systems
115
-
116
- ## Next Steps (v0.5.0 continued)
117
-
118
- **Remaining work:**
119
- 1. Update `start.js` to load credentials from keychain
120
- 2. Update `init.js` to detect keychain credentials
121
- 3. Implement credential resolution priority: `.env.local` → keychain → defaults
122
- 4. Create global registry (`~/.buwp-local/registry.json`)
123
- 5. Update documentation
124
-
125
- **Future enhancements (v0.6.0+):**
126
- - Cross-platform support (Windows Credential Manager, Linux Secret Service)
127
- - Project-specific credential overrides
128
- - Credential import/export
129
- - Team credential sharing mechanisms
130
-
131
- ## Benefits Delivered
132
-
133
- ✅ **One-time setup** - Enter credentials once, use across all projects
134
- ✅ **Secure storage** - Leverages macOS keychain encryption
135
- ✅ **Simple CLI** - Intuitive subcommands for all operations
136
- ✅ **Backward compatible** - .env.local still works as override
137
- ✅ **Developer friendly** - Clear messages and helpful status command
138
- ✅ **Production ready** - Fully tested and linted
139
-
140
- This implementation solves the multi-repo credential fatigue problem while maintaining backward compatibility and providing a secure, native macOS integration.
@@ -1,11 +0,0 @@
1
- It's often convenient to store a password in the macOS system keychain and retrieve it inside a shell script.
2
-
3
- Here's the bash command for setting a password:
4
-
5
- security add-generic-password -s "Keychain item name here" -a "username here" -p
6
- Then enter your password when prompted.
7
-
8
- After you run this once, you can retrieve the password in a script like this:
9
-
10
- PASSWORD=`security find-generic-password -s "Keychain item name here" -a "username here" -w`
11
- You can then use $PASSWORD whenever you need the password in your script.