@bobfrankston/npmglobalize 1.0.115 → 1.0.116
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/README.md +10 -0
- package/lib.js +37 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -127,6 +127,16 @@ npmglobalize --fix # Runs npm audit fix
|
|
|
127
127
|
npmglobalize --no-fix
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
+
### 🔑 OAuth Credentials Handling
|
|
131
|
+
|
|
132
|
+
`npmglobalize` automatically detects `credentials.json` files and handles them based on OAuth app type:
|
|
133
|
+
|
|
134
|
+
- **Desktop/installed apps** (`"installed"` key in JSON): The `client_secret` is just a public app registration ID, not a real secret. Google's own docs state: *"the client_secret is obviously not treated as a secret."* These files are kept in the repo — `!credentials.json` is added to `.gitignore`/`.npmignore` to override any broader ignore patterns.
|
|
135
|
+
|
|
136
|
+
- **Web apps** (`"web"` key in JSON): The `client_secret` is a real secret. These files are automatically added to `.gitignore`/`.npmignore` to prevent accidental exposure.
|
|
137
|
+
|
|
138
|
+
This distinction also drives the **push protection auto-bypass**: when GitHub blocks a push because it detects an OAuth client secret, `npmglobalize` checks the credential file type. For installed apps, it auto-bypasses (marking as `false_positive`) since the credential is public by design.
|
|
139
|
+
|
|
130
140
|
### 🔄 File Reference Management
|
|
131
141
|
|
|
132
142
|
**Default behavior** (restore file: references after publish):
|
package/lib.js
CHANGED
|
@@ -1440,30 +1440,51 @@ function parsePushProtection(errorOutput, cwd) {
|
|
|
1440
1440
|
return result;
|
|
1441
1441
|
}
|
|
1442
1442
|
result.detected = true;
|
|
1443
|
-
//
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1443
|
+
// Match secret blocks using a single regex across any dash characters
|
|
1444
|
+
// Pattern: "-- Type Name ---..." then "path: file:line" then "unblock-secret/id" URL
|
|
1445
|
+
// Handles em-dash (—), en-dash (–), and regular dash (-)
|
|
1446
|
+
const secretRegex = /[-\u2014\u2013]{2,}\s+(.+?)\s+[-\u2014\u2013]{2,}[\s\S]*?path:\s+(\S+?)(?::\d+)?\s[\s\S]*?(https:\/\/github\.com\/\S+\/unblock-secret\/\S+)/g;
|
|
1447
|
+
let match;
|
|
1448
|
+
while ((match = secretRegex.exec(cleaned)) !== null) {
|
|
1449
|
+
result.secrets.push({
|
|
1450
|
+
type: match[1].trim(),
|
|
1451
|
+
file: match[2].trim(),
|
|
1452
|
+
unblockUrl: match[3].trim()
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
// If regex didn't match (encoding issues), fall back to finding unblock URLs + paths
|
|
1456
|
+
if (result.secrets.length === 0) {
|
|
1457
|
+
const urlRegex = /(https:\/\/github\.com\/\S+\/unblock-secret\/\S+)/g;
|
|
1458
|
+
const pathRegex = /path:\s+(\S+?)(?::\d+)?\s/g;
|
|
1459
|
+
const urls = [];
|
|
1460
|
+
const files = [];
|
|
1461
|
+
let m;
|
|
1462
|
+
while ((m = urlRegex.exec(cleaned)) !== null)
|
|
1463
|
+
urls.push(m[1].trim());
|
|
1464
|
+
while ((m = pathRegex.exec(cleaned)) !== null)
|
|
1465
|
+
files.push(m[1].trim());
|
|
1466
|
+
// Try to detect secret type from text
|
|
1467
|
+
const hasOAuth = cleaned.toLowerCase().includes('oauth');
|
|
1468
|
+
const secretType = hasOAuth ? 'Google OAuth Credential' : 'Secret';
|
|
1469
|
+
for (let i = 0; i < Math.max(urls.length, files.length); i++) {
|
|
1470
|
+
result.secrets.push({
|
|
1471
|
+
type: secretType,
|
|
1472
|
+
file: files[i] || '',
|
|
1473
|
+
unblockUrl: urls[i] || ''
|
|
1474
|
+
});
|
|
1456
1475
|
}
|
|
1457
1476
|
}
|
|
1458
1477
|
// Check if all detected secrets are from Google OAuth installed apps (safe to include)
|
|
1459
1478
|
if (result.secrets.length > 0) {
|
|
1460
1479
|
result.allInstalledOAuth = result.secrets.every(s => {
|
|
1461
|
-
if (!s.type.toLowerCase().includes('oauth'))
|
|
1462
|
-
return false;
|
|
1463
1480
|
if (!s.file)
|
|
1464
1481
|
return false;
|
|
1482
|
+
// Check by type name OR by inspecting the actual credential file
|
|
1465
1483
|
const credType = detectCredentialsTypeFromFile(path.join(cwd, s.file));
|
|
1466
|
-
|
|
1484
|
+
if (credType === 'installed')
|
|
1485
|
+
return true;
|
|
1486
|
+
// Also match if the type name mentions OAuth (even if file check failed)
|
|
1487
|
+
return s.type.toLowerCase().includes('oauth') && credType !== 'web';
|
|
1467
1488
|
});
|
|
1468
1489
|
}
|
|
1469
1490
|
return result;
|