Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aeccbcbbe9 | |||
| 15b154fc8d |
@@ -6,6 +6,23 @@ correspond to git tags (`vX.Y.Z`) and `nodejs/package.json`'s `version`.
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.13.0] - 2026-08-01
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **Secrets now load from OpenBao at boot** via
|
||||||
|
[@simpleworkjs/bao-conf](https://simpleworkjs.github.io/bao-conf/), which
|
||||||
|
deep-merges `secret/proxy/conf` over the file-loaded config. The proxy
|
||||||
|
authenticates to OpenBao with a scoped `VAULT_TOKEN` (policy `proxy` —
|
||||||
|
read-only on its own path), never the root token. Because the OIDC
|
||||||
|
`clientSecret` is captured at require time inside `createOidcClient` (during
|
||||||
|
`require('../models')`, which `require('../app')` triggers transitively),
|
||||||
|
`bin/www` now defers `require('../app')` until after `bao-conf.init()`
|
||||||
|
resolves. Fail-soft: if OpenBao is unreachable, boot continues from
|
||||||
|
`CONF_SECRETS`. The `config/proxy-secrets.js` file is now an operator-edit
|
||||||
|
seed artifact (gitignored); OpenBao is authoritative. See theta-env's
|
||||||
|
[Secrets docs](https://theta42.github.io/theta-env/secrets/).
|
||||||
|
- Bumped package version to track the release tag.
|
||||||
|
|
||||||
## [1.12.1] - 2026-08-01
|
## [1.12.1] - 2026-08-01
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -162,6 +162,23 @@ docker compose exec proxy tail -f /var/log/nginx/error.log
|
|||||||
docker compose logs --tail=200 --since=10m proxy
|
docker compose logs --tail=200 --since=10m proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
Secrets are loaded from **OpenBao** at boot via
|
||||||
|
[@simpleworkjs/bao-conf](https://simpleworkjs.github.io/bao-conf/), which
|
||||||
|
deep-merges `secret/proxy/conf` over the file-loaded config. The proxy's OIDC
|
||||||
|
`clientSecret` is captured at require time (inside `createOidcClient` during
|
||||||
|
`require('../models')`), so `bin/www` runs `bao-conf.init()` **before**
|
||||||
|
`require('../app')` (which transitively loads models). Fail-soft: if OpenBao is
|
||||||
|
unreachable, boot continues from `CONF_SECRETS`. The proxy authenticates to
|
||||||
|
OpenBao with the scoped `VAULT_TOKEN` (env, policy `proxy` — read only
|
||||||
|
`secret/proxy/conf`), never the root token.
|
||||||
|
|
||||||
|
The `config/proxy-secrets.js` file is an operator-edit seed artifact
|
||||||
|
(gitignored); the bootstrap writes the generated OAuth client creds into
|
||||||
|
OpenBao, which is authoritative. For the full architecture see theta-env's
|
||||||
|
**[Secrets docs](https://theta42.github.io/theta-env/secrets/)**.
|
||||||
|
|
||||||
## Manual Installation
|
## Manual Installation
|
||||||
|
|
||||||
For manual installation or other distributions, see the detailed steps below.
|
For manual installation or other distributions, see the detailed steps below.
|
||||||
|
|||||||
+78
-65
@@ -4,34 +4,91 @@
|
|||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var app = require('../app');
|
|
||||||
var debug = require('debug')('proxy-api:server');
|
|
||||||
var http = require('http');
|
|
||||||
const conf = require('@simpleworkjs/conf');
|
const conf = require('@simpleworkjs/conf');
|
||||||
|
const debug = require('debug')('proxy-api:server');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
/**
|
// @simpleworkjs/conf loads ./config/proxy-secrets.js synchronously, then
|
||||||
* Get port from environment and store in Express.
|
// @simpleworkjs/bao-conf deep-merges secret/proxy/conf from OpenBao over it.
|
||||||
*/
|
// The OIDC clientSecret is captured at require time inside models (via
|
||||||
|
// createOidcClient), and require('../app') transitively loads models, so the
|
||||||
|
// OpenBao fetch MUST resolve before require('../app'). Fail-soft: if OpenBao
|
||||||
|
// is unreachable, init() leaves conf as the file-loaded fallback and boot
|
||||||
|
// continues from ./config/proxy-secrets.js.
|
||||||
|
require('@simpleworkjs/bao-conf').init({ path: 'proxy', conf }).then(() => {
|
||||||
|
var app = require('../app'); // models + createOidcClient now see merged conf
|
||||||
|
|
||||||
var port = normalizePort(process.env.NODE_PORT || conf.port || '3000');
|
/**
|
||||||
app.set('port', port);
|
* Get port from environment and store in Express.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
var port = normalizePort(process.env.NODE_PORT || conf.port || '3000');
|
||||||
* Create HTTP server.
|
app.set('port', port);
|
||||||
*/
|
|
||||||
|
|
||||||
var server = http.createServer(app);
|
/**
|
||||||
|
* Create HTTP server.
|
||||||
|
*/
|
||||||
|
|
||||||
var io = require('socket.io')(server);
|
var server = http.createServer(app);
|
||||||
app.io = io;
|
|
||||||
|
|
||||||
/**
|
var io = require('socket.io')(server);
|
||||||
* Listen on provided port, on all network interfaces.
|
app.io = io;
|
||||||
*/
|
|
||||||
|
|
||||||
server.listen(port);
|
/**
|
||||||
server.on('error', onError);
|
* Listen on provided port, on all network interfaces.
|
||||||
server.on('listening', onListening);
|
*/
|
||||||
|
|
||||||
|
server.listen(port);
|
||||||
|
server.on('error', onError);
|
||||||
|
server.on('listening', onListening);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "error" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onError(error) {
|
||||||
|
if (error.syscall !== 'listen') {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bind = typeof port === 'string'
|
||||||
|
? 'Pipe ' + port
|
||||||
|
: 'Port ' + port;
|
||||||
|
|
||||||
|
// handle specific listen errors with friendly messages
|
||||||
|
switch (error.code) {
|
||||||
|
case 'EACCES':
|
||||||
|
console.error(bind + ' requires elevated privileges');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
|
console.error(bind + ' is already in use');
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for HTTP server "listening" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onListening() {
|
||||||
|
var addr = server.address();
|
||||||
|
var bind = typeof addr === 'string'
|
||||||
|
? 'pipe ' + addr
|
||||||
|
: 'port ' + addr.port;
|
||||||
|
console.log('Listening on ' + bind);
|
||||||
|
|
||||||
|
for(let listener of app.onListen){
|
||||||
|
listener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('boot failed:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a port into a number, string, or false.
|
* Normalize a port into a number, string, or false.
|
||||||
@@ -51,48 +108,4 @@ function normalizePort(val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "error" event.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function onError(error) {
|
|
||||||
if (error.syscall !== 'listen') {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bind = typeof port === 'string'
|
|
||||||
? 'Pipe ' + port
|
|
||||||
: 'Port ' + port;
|
|
||||||
|
|
||||||
// handle specific listen errors with friendly messages
|
|
||||||
switch (error.code) {
|
|
||||||
case 'EACCES':
|
|
||||||
console.error(bind + ' requires elevated privileges');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
case 'EADDRINUSE':
|
|
||||||
console.error(bind + ' is already in use');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "listening" event.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function onListening() {
|
|
||||||
var addr = server.address();
|
|
||||||
var bind = typeof addr === 'string'
|
|
||||||
? 'pipe ' + addr
|
|
||||||
: 'port ' + addr.port;
|
|
||||||
console.log('Listening on ' + bind);
|
|
||||||
|
|
||||||
for(let listener of app.onListen){
|
|
||||||
listener()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
+13
@@ -12,6 +12,7 @@
|
|||||||
"@fortawesome/fontawesome-free": "^7.3.0",
|
"@fortawesome/fontawesome-free": "^7.3.0",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@simpleworkjs/app-stack": "^1.0.0",
|
"@simpleworkjs/app-stack": "^1.0.0",
|
||||||
|
"@simpleworkjs/bao-conf": "^1.0.0",
|
||||||
"@simpleworkjs/conf": "^1.2.0",
|
"@simpleworkjs/conf": "^1.2.0",
|
||||||
"@simpleworkjs/frontend": "^0.2.7",
|
"@simpleworkjs/frontend": "^0.2.7",
|
||||||
"@simpleworkjs/ldap": "^1.0.0",
|
"@simpleworkjs/ldap": "^1.0.0",
|
||||||
@@ -297,6 +298,18 @@
|
|||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@simpleworkjs/bao-conf": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@simpleworkjs/bao-conf/-/bao-conf-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-HxB2ohFuDKbwTfNh5dXCot0dd6qoP+3Ebz1xKH0eOhKNVNMjHU1p7XZv2VTe+VnHn+DV22Eh8lAgWxnX/pkXUw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"extend": "^3.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@simpleworkjs/conf": {
|
"node_modules/@simpleworkjs/conf": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@simpleworkjs/conf/-/conf-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@simpleworkjs/conf/-/conf-1.2.0.tgz",
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "proxy-api",
|
"name": "proxy-api",
|
||||||
"version": "1.9.0",
|
"version": "1.13.0",
|
||||||
"author": [
|
"author": [
|
||||||
{
|
{
|
||||||
"name": "William Mantly",
|
"name": "William Mantly",
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"@fortawesome/fontawesome-free": "^7.3.0",
|
"@fortawesome/fontawesome-free": "^7.3.0",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@simpleworkjs/app-stack": "^1.0.0",
|
"@simpleworkjs/app-stack": "^1.0.0",
|
||||||
|
"@simpleworkjs/bao-conf": "^1.0.0",
|
||||||
"@simpleworkjs/conf": "^1.2.0",
|
"@simpleworkjs/conf": "^1.2.0",
|
||||||
"@simpleworkjs/frontend": "^0.2.7",
|
"@simpleworkjs/frontend": "^0.2.7",
|
||||||
"@simpleworkjs/ldap": "^1.0.0",
|
"@simpleworkjs/ldap": "^1.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user