Skip to content

Commit a994e76

Browse files
authored
Merge pull request #208 from bcgov/bucket-check
Validate default bucket configuration on startup
2 parents 7f8701a + d5941ae commit a994e76

File tree

18 files changed

+81
-90
lines changed

18 files changed

+81
-90
lines changed

.github/environments/values.dev.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
features:
33
basicAuth: true
4+
defaultBucket: false
45
oidcAuth: true
56

67
autoscaling:
@@ -18,15 +19,12 @@ config:
1819
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuy7zfh2ZgpDV5mH/aXyLDTddZK81rGakJcTy4KvCNOkDDxt1KAhW02lmbCo8YhHCOzjNZBp1+Vi6QiMRgBqAe2GTPZYEiV70aXfROGZe3Nvwcjbtki6HoyRte3SpqLJEIPL2F+hjJkw1UPGnjPTWZkEx9p74b9i3BjuE8RnjJ0Sza2MWw83zoQUZEJRGiopSL0yuVej6t2LO2btVdVf7QuZfPt9ehkcQYlPKpVvJA+pfeqPAdnNt7OjEIeYxinjurZr8Z04hz8UhkRefcWlSbFzFQYmL7O7iArjW0bsSvq8yNUd5r0KCOQkFduwZy26yTzTxj8OLFT91fEmbBBl4rQIDAQAB
1920
KC_REALM: standard
2021
KC_SERVERURL: "https://dev.loginproxy.gov.bc.ca/auth"
21-
OBJECTSTORAGE_BUCKET: egejyy
22-
OBJECTSTORAGE_TEMP_EXPIRESIN: "300"
23-
OBJECTSTORAGE_ENDPOINT: "https://nrs.objectstore.gov.bc.ca"
24-
# OBJECTSTORAGE_KEY: ~
2522
SERVER_BODYLIMIT: 30mb
2623
# SERVER_LOGFILE: ~
2724
SERVER_LOGLEVEL: http
2825
SERVER_PORT: "3000"
2926
SERVER_PRIVACY_MASK: "true"
27+
SERVER_TEMP_EXPIRESIN: "300"
3028

3129
patroni:
3230
enabled: true

.github/environments/values.pr.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
features:
33
basicAuth: true
44
oidcAuth: true
5+
defaultBucket: false
56

67
patroni:
78
enabled: true

.github/environments/values.prod.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
features:
33
basicAuth: true
4+
defaultBucket: true
45
oidcAuth: true
56

67
autoscaling:
@@ -18,15 +19,12 @@ config:
1819
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmHiuPKOkpkq4GXN1ktr23rJtDl6Vdu/Y37ZAd3PnQ8/IDfAODvy1Y81aAUZicKe9egolv+OTRANN3yOg+TAbRhkeXLE5p/473EK0aQ0NazTCuWo6Am3oDQ7Yt8x0pw56/qcLtkTuXNyo5EnVV2Z2BzCnnaL31JOhyitolku0DNT6GDoRBmT4o2ItqEVHk5nM25cf1t2zbwI2790W6if1B2qVRkxxivS8tbH7nYC61Is3XCPockKptkH22cm2ZQJmtYd5sZKuXaGsvtyzHmn8/l0Kd1xnHmUu4JNuQ67YiNZGu3hOkrF0Js3BzAk1Qm4kvYRaxbJFCs/qokLZ4Z0W9wIDAQAB
1920
KC_REALM: standard
2021
KC_SERVERURL: "https://loginproxy.gov.bc.ca/auth"
21-
OBJECTSTORAGE_BUCKET: egejyy
22-
OBJECTSTORAGE_TEMP_EXPIRESIN: "300"
23-
OBJECTSTORAGE_ENDPOINT: "https://nrs.objectstore.gov.bc.ca"
24-
# OBJECTSTORAGE_KEY: ~
2522
SERVER_BODYLIMIT: 30mb
2623
# SERVER_LOGFILE: ~
2724
SERVER_LOGLEVEL: http
2825
SERVER_PORT: "3000"
2926
SERVER_PRIVACY_MASK: "true"
27+
SERVER_TEMP_EXPIRESIN: "300"
3028

3129
patroni:
3230
enabled: true

.github/environments/values.test.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
features:
33
basicAuth: true
4+
defaultBucket: false
45
oidcAuth: true
56

67
autoscaling:
@@ -18,15 +19,12 @@ config:
1819
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiFdv9GA83uHuy8Eu9yiZHGGF9j6J8t7FkbcpaN81GDjwbjsIJ0OJO9dKRAx6BAtTC4ubJTBJMPvQER5ikOhIeBi4o25fg61jpgsU6oRZHkCXc9gX6mrjMjbsPaf3/bjjYxP5jicBDJQeD1oRa24+tiGggoQ7k6gDEN+cRYqqNpzC/GQbkUPk8YsgroncEgu8ChMh/3ERsLV2zorchMANUq76max16mHrhtWIQxrb/STpSt4JuSlUzzBV/dcXjJe5gywZHe0jAutFhNqjHzHdgyaC4RAd3eYQo+Kl/JOgy2AZrnx+CiPmvOJKe9tAW4k4H087ng8aVE40v4HW/FEbnwIDAQAB
1920
KC_REALM: standard
2021
KC_SERVERURL: "https://test.loginproxy.gov.bc.ca/auth"
21-
OBJECTSTORAGE_BUCKET: egejyy
22-
OBJECTSTORAGE_TEMP_EXPIRESIN: "300"
23-
OBJECTSTORAGE_ENDPOINT: "https://nrs.objectstore.gov.bc.ca"
24-
# OBJECTSTORAGE_KEY: ~
2522
SERVER_BODYLIMIT: 30mb
2623
# SERVER_LOGFILE: ~
2724
SERVER_LOGLEVEL: http
2825
SERVER_PORT: "3000"
2926
SERVER_PRIVACY_MASK: "true"
27+
SERVER_TEMP_EXPIRESIN: "300"
3028

3129
patroni:
3230
enabled: true

app/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ The following variables enable and enforce the use of OIDC Bearer Authentication
8282

8383
| Config Var | Env Var | Default | Notes |
8484
| --- | --- | --- | --- |
85+
| `enabled` | `OBJECTSTORAGE_ENABLED` | | Whether to run COMS with a default bucket |
8586
| `accessKeyId` | `OBJECTSTORAGE_ACCESSKEYID` | | The Access Key for your S3 compatible object storage account |
8687
| `bucket` | `OBJECTSTORAGE_BUCKET` | | The object storage bucket name |
87-
| `defaultTempExpiresIn` | `OBJECTSTORAGE_TEMP_EXPIRESIN` | 300 | The expiry time for pre-signed URLs to objects in seconds |
8888
| `endpoint` | `OBJECTSTORAGE_ENDPOINT` | | Object store URL. eg: `https://nrs.objectstore.gov.bc.ca` |
8989
| `key` | `OBJECTSTORAGE_KEY` | | The base path for storage location |
9090
| `secretAccessKey` | `OBJECTSTORAGE_SECRETACCESSKEY` | | The Secret Access Key for your S3 compatible object storage account |
@@ -96,6 +96,7 @@ The following variables alter the general Express application behavior. For most
9696
| Config Var | Env Var | Default | Notes |
9797
| --- | --- | --- | --- |
9898
| `bodyLimit` | `SERVER_BODYLIMIT` | 30mb | Maximum body size accepted for parsing to JSON body |
99+
| `defaultTempExpiresIn` | `SERVER_TEMP_EXPIRESIN` | 300 | The expiry time for pre-signed S3 URLs to objects in seconds |
99100
| `logFile` | `SERVER_LOGFILE` | | Writes logs to the following file only if defined |
100101
| `logLevel` | `SERVER_LOGLEVEL` | http | The logging level of COMS |
101102
| `passphrase` | `SERVER_PASSPHRASE` | | A key to encrypt/decrypt bucket secretAccessKey's saved to the database |
@@ -122,6 +123,7 @@ Run COMS in **Unauthenticated mode** (replace environment values as necessary)
122123

123124
``` sh
124125
docker run -it --rm -p 3000:3000 \
126+
-e OBJECTSTORAGE_ENABLED=true \
125127
-e OBJECTSTORAGE_ACCESSKEYID=<Access Key ID for your S3 account> \
126128
-e OBJECTSTORAGE_BUCKET=<Object storage bucket name> \
127129
-e OBJECTSTORAGE_ENDPOINT=<Object store URL. eg: https://nrs.objectstore.gov.bc.ca> \
@@ -134,6 +136,7 @@ Run COMS in **Basic Auth mode** (replace environment values as necessary)
134136

135137
``` sh
136138
docker run -it --rm -p 3000:3000 \
139+
-e OBJECTSTORAGE_ENABLED=true \
137140
-e OBJECTSTORAGE_ACCESSKEYID=<Access Key ID for your S3 account> \
138141
-e OBJECTSTORAGE_BUCKET=<Object storage bucket name> \
139142
-e OBJECTSTORAGE_ENDPOINT=<Object store URL. eg: https://nrs.objectstore.gov.bc.ca> \
@@ -158,6 +161,7 @@ Run COMS in **OIDC Auth Mode** (replace environment values as necessary)
158161

159162
``` sh
160163
docker run -it --rm -p 3000:3000 \
164+
-e OBJECTSTORAGE_ENABLED=true \
161165
-e OBJECTSTORAGE_ACCESSKEYID=<Access Key ID for your S3 account> \
162166
-e OBJECTSTORAGE_BUCKET=<Object storage bucket name> \
163167
-e OBJECTSTORAGE_ENDPOINT=<Object store URL. eg: https://nrs.objectstore.gov.bc.ca> \
@@ -178,6 +182,7 @@ Run COMS in **Full Auth Mode** (replace environment values as necessary)
178182

179183
``` sh
180184
docker run -it --rm -p 3000:3000 \
185+
-e OBJECTSTORAGE_ENABLED=true \
181186
-e OBJECTSTORAGE_ACCESSKEYID=<Access Key ID for your S3 account> \
182187
-e OBJECTSTORAGE_BUCKET=<Object storage bucket name> \
183188
-e OBJECTSTORAGE_ENDPOINT=<Object store URL. eg: https://nrs.objectstore.gov.bc.ca> \
@@ -233,6 +238,7 @@ To run COMS in Full Auth mode you will want your `local.json` to have the follow
233238
"serverUrl": "<OIDC server auth URL>"
234239
},
235240
"objectStorage": {
241+
"enabled": true,
236242
"secretAccessKey": "<Secret Access Key for your S3 compatible object storage account>",
237243
"key": "<base path for storage location>",
238244
"accessKeyId": "<Access Key ID for your S3 account>",

app/app.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const QueueManager = require('./src/components/queueManager');
1313
const { getAppAuthMode, getGitRevision } = require('./src/components/utils');
1414
const DataConnection = require('./src/db/dataConnection');
1515
const v1Router = require('./src/routes/v1');
16+
const { readUnique } = require('./src/services/bucket');
1617

1718
const dataConnection = new DataConnection();
1819
const queueManager = new QueueManager();
@@ -215,6 +216,12 @@ function initializeConnections() {
215216
if (state.connections.data) {
216217
log.info('DataConnection Reachable', { function: 'initializeConnections' });
217218
}
219+
if (config.has('objectStorage.enabled')) {
220+
readUnique(config.get('objectStorage')).then(() => {
221+
log.error('Default bucket cannot also exist in database', { function: 'initializeConnections' });
222+
fatalErrorHandler();
223+
}).catch(() => { });
224+
}
218225
})
219226
.catch(error => {
220227
log.error(`Initialization failed: Database OK = ${state.connections.data}`, { function: 'initializeConnections' });

app/config/custom-environment-variables.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@
2525
"objectStorage": {
2626
"accessKeyId": "OBJECTSTORAGE_ACCESSKEYID",
2727
"bucket": "OBJECTSTORAGE_BUCKET",
28-
"defaultTempExpiresIn": "OBJECTSTORAGE_TEMP_EXPIRESIN",
28+
"enabled": "OBJECTSTORAGE_ENABLED",
2929
"endpoint": "OBJECTSTORAGE_ENDPOINT",
3030
"key": "OBJECTSTORAGE_KEY",
3131
"secretAccessKey": "OBJECTSTORAGE_SECRETACCESSKEY"
3232
},
3333
"server": {
3434
"bodyLimit": "SERVER_BODYLIMIT",
35+
"defaultTempExpiresIn": "SERVER_TEMP_EXPIRESIN",
3536
"hardReset": "SERVER_HARDRESET",
3637
"logFile": "SERVER_LOGFILE",
3738
"logLevel": "SERVER_LOGLEVEL",

app/config/default.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@
77
"poolMax": "10",
88
"username": "app"
99
},
10-
"objectStorage": {
11-
"defaultTempExpiresIn": "300"
12-
},
1310
"server": {
1411
"bodyLimit": "30mb",
12+
"defaultTempExpiresIn": "300",
1513
"logLevel": "http",
1614
"maxRetries": "3",
1715
"port": "3000"

app/src/components/utils.js

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,42 +61,44 @@ const utils = {
6161

6262
/**
6363
* @function getBucket
64-
* Acquire core S3 bucket credential information with graceful default fallback
65-
* @param {string} [bucketId=undefined] An optional bucketId to lookup
66-
* @param {boolean} [throwable=false] Throws an error if no `bucketId` is found
64+
* Acquire core S3 bucket credential information from database or configuration
65+
* @param {string} [bucketId=undefined] An optional bucket ID to query database for bucket
6766
* @returns {object} An object containing accessKeyId, bucket, endpoint, key,
6867
* region and secretAccessKey attributes
69-
* @throws If there are no records found with `bucketId` and `throwable` is true
68+
* @throws If there are no records found with `bucketId` or, if `bucketId` is undefined,
69+
* no bucket details exist in the configuration
7070
*/
71-
async getBucket(bucketId = undefined, throwable = false) {
72-
const data = {
73-
accessKeyId: config.get('objectStorage.accessKeyId'),
74-
bucket: config.get('objectStorage.bucket'),
75-
endpoint: config.get('objectStorage.endpoint'),
76-
key: config.get('objectStorage.key'),
77-
region: DEFAULTREGION,
78-
secretAccessKey: config.get('objectStorage.secretAccessKey')
79-
};
80-
81-
if (bucketId) {
82-
// Function scoped import to avoid circular dependencies
83-
const { bucketService } = require('../services');
84-
85-
try {
86-
const bucketData = await bucketService.read(bucketId);
71+
async getBucket(bucketId = undefined) {
72+
try {
73+
const data = { region: DEFAULTREGION };
74+
if (bucketId) {
75+
// Function scoped import to avoid circular dependencies
76+
const { read } = require('../services/bucket');
77+
const bucketData = await read(bucketId);
78+
8779
data.accessKeyId = bucketData.accessKeyId;
8880
data.bucket = bucketData.bucket;
8981
data.endpoint = bucketData.endpoint;
9082
data.key = bucketData.key;
9183
data.secretAccessKey = bucketData.secretAccessKey;
9284
if (bucketData.region) data.region = bucketData.region;
93-
} catch (err) {
94-
log.warn(err.message, { function: 'getBucket' });
95-
if (throwable) throw new Problem(404, { details: err.message });
85+
} else if (config.has('objectStorage') && config.has('objectStorage.enabled')) {
86+
data.accessKeyId = config.get('objectStorage.accessKeyId');
87+
data.bucket = config.get('objectStorage.bucket');
88+
data.endpoint = config.get('objectStorage.endpoint');
89+
data.key = config.get('objectStorage.key');
90+
data.secretAccessKey = config.get('objectStorage.secretAccessKey');
91+
if (config.has('objectStorage.region')) {
92+
data.region = config.get('objectStorage.region');
93+
}
94+
} else {
95+
throw new Error('Unable to get bucket');
9696
}
97+
return data;
98+
} catch (err) {
99+
log.error(err.message, { function: 'getBucket' });
100+
throw new Problem(404, { details: err.message });
97101
}
98-
99-
return data;
100102
},
101103

102104
/**

app/src/controllers/object.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ const controller = {
239239
}
240240

241241
// Preflight existence check for bucketId
242-
const { key: bucketKey } = await getBucket(bucketId, true);
242+
const { key: bucketKey } = await getBucket(bucketId);
243243

244244
const objId = uuidv4();
245245
const data = {
@@ -373,7 +373,7 @@ const controller = {
373373
}
374374

375375
// Preflight existence check for bucketId
376-
const { key: bucketKey } = await getBucket(bucketId, true);
376+
const { key: bucketKey } = await getBucket(bucketId);
377377

378378
bb.on('file', async (name, stream, info) => {
379379
try {
@@ -1059,7 +1059,7 @@ const controller = {
10591059

10601060
// Preflight existence check for bucketId
10611061
const bucketId = req.currentObject?.bucketId;
1062-
const { key: bucketKey } = await getBucket(bucketId, true);
1062+
const { key: bucketKey } = await getBucket(bucketId);
10631063

10641064
const filename = req.currentObject?.path.match(/(?!.*\/)(.*)$/)[0];
10651065
const objId = addDashesToUuid(req.params.objectId);
@@ -1196,7 +1196,7 @@ const controller = {
11961196

11971197
// Preflight existence check for bucketId
11981198
const bucketId = req.currentObject?.bucketId;
1199-
const { key: bucketKey } = await getBucket(bucketId, true);
1199+
const { key: bucketKey } = await getBucket(bucketId);
12001200

12011201
bb.on('file', async (name, stream, info) => {
12021202
try {

0 commit comments

Comments
 (0)