Repository: OWASP/threat-dragon
Pull request #1017 (2024-07-13 20:45:14)

backward compatible for env vars GITHUB_USE_SEARCH and GITHUB_SEARCH_QUERY
**Summary**:
it would be good to provide backward compatiblity for env vars GITHUB_USE_SEARCH and GITHUB_SEARCH_QUERY
these are probably in use so we should not break that functionality
Only for Github - the bitbucket and gitlab env vars did not work previously so they will not have been used 

**Description for the changelog**:
make backward compatible for github search env vars

**Other info**:



Patch:
diff --git a/.github/workflows/housekeeping.yaml b/.github/workflows/housekeeping.yaml
index 06d4bd2c..d99c9fe4 100644
--- a/.github/workflows/housekeeping.yaml
+++ b/.github/workflows/housekeeping.yaml
@@ -65,7 +65,7 @@ jobs:
           ref: main
 
       - name: Run vulnerability scanner
-        uses: aquasecurity/trivy-action@0.23.0
+        uses: aquasecurity/trivy-action@0.24.0
         with:
           image-ref: '${{ env.IMAGE_NAME }}:latest'
           format: 'template'
diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml
index 3896c99a..3e3b97ad 100644
--- a/.github/workflows/pull_request.yaml
+++ b/.github/workflows/pull_request.yaml
@@ -383,7 +383,7 @@ jobs:
           docker load --input /tmp/${{ env.IMAGE_NAME }}.tar
 
       - name: Run Trivy vulnerability scanner
-        uses: aquasecurity/trivy-action@0.23.0
+        uses: aquasecurity/trivy-action@0.24.0
         with:
           image-ref: '${{ env.IMAGE_NAME }}'
           format: 'table'
diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml
index b28716ff..b43d1306 100644
--- a/.github/workflows/push.yaml
+++ b/.github/workflows/push.yaml
@@ -433,7 +433,7 @@ jobs:
         uses: actions/checkout@v4.1.1
 
       - name: Run Trivy vulnerability scanner
-        uses: aquasecurity/trivy-action@0.23.0
+        uses: aquasecurity/trivy-action@0.24.0
         with:
           image-ref: '${{ env.IMAGE_NAME }}'
           format: 'table'
diff --git a/.gitignore b/.gitignore
index 2516638f..83daaf5b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,12 +46,43 @@
 
 # Express server
 !td.server
-!td.server/src/**/*.js
-!td.server/test/**/*.js
-!td.server/**/*.js
-!td.server/**/**/*.js
+!td.server/src/
+!td.server/src/*.js
+!td.server/src/config/
+!td.server/src/config/*.js
+!td.server/src/controllers/
+!td.server/src/controllers/*.js
+!td.server/src/env/
+!td.server/src/env/*.js
+!td.server/src/helpers/
+!td.server/src/helpers/*.js
+!td.server/src/providers/
+!td.server/src/providers/*.js
+!td.server/src/repositories/
+!td.server/src/repositories/*.js
+!td.server/test/
+!td.server/test/*.spec.js
+!td.server/test/config/
+!td.server/test/config/*.spec.js
+!td.server/test/controllers/
+!td.server/test/controllers/*.spec.js
+!td.server/test/env/
+!td.server/test/env/*.spec.js
+!td.server/test/helpers/
+!td.server/test/helpers/*.spec.js
+!td.server/test/mocks/
+!td.server/test/mocks/*mock*js
+!td.server/test/providers/
+!td.server/test/providers/*.spec.js
+!td.server/test/public/
+!td.server/test/public/*.ico
+!td.server/test/repositories/
+!td.server/test/repositories/*.spec.js
 !td.server/.babelrc
+!td.server/.eslintrc.js
 !td.server/README.md
+!td.server/dev.js
+!td.server/index.js
 !td.server/package.json
 !td.server/package-lock.json
 
diff --git a/td.server/src/controllers/threatmodelcontroller.js b/td.server/src/controllers/threatmodelcontroller.js
index e43bd781..93b99ecd 100644
--- a/td.server/src/controllers/threatmodelcontroller.js
+++ b/td.server/src/controllers/threatmodelcontroller.js
@@ -12,9 +12,10 @@ const repos = (req, res) => responseWrapper.sendResponseAsync(async () => {
     const page = req.query.page || 1;
     let reposResp;
     let repos;
-    if (env.get().config.REPO_USE_SEARCH === 'true') {
+    // backwardly compatible with previous use of env vars GITHUB_USE_SEARCH and GITHUB_SEARCH_QUERY
+    if (env.get().config.REPO_USE_SEARCH === 'true' || env.get().config.GITHUB_USE_SEARCH === 'true') {
         logger.debug('Using searchAsync');
-        const searchQuery = env.get().config.REPO_SEARCH_QUERY;
+        const searchQuery = env.get().config.REPO_SEARCH_QUERY ?? env.get().config.GITHUB_SEARCH_QUERY;
         reposResp = await repository.searchAsync(page, req.provider.access_token, searchQuery);
         repos = reposResp[0].items ?? reposResp[0];
     } else {
diff --git a/td.server/src/env/Bitbucket.js b/td.server/src/env/Bitbucket.js
index 1bf27aa4..6bcc5e5e 100644
--- a/td.server/src/env/Bitbucket.js
+++ b/td.server/src/env/Bitbucket.js
@@ -14,12 +14,10 @@ class BitbucketEnv extends Env {
         return [
             { key: 'CLIENT_ID', required: false },
             { key: 'CLIENT_SECRET', required: false },
-            { key: 'SCOPE', required: false, defaultValue: 'public_repo' },
+            { key: 'SCOPE', required: false, defaultValue: 'repository:read' },
             { key: 'ENTERPRISE_HOSTNAME', required: false },
             { key: 'ENTERPRISE_PORT', required: false, defaultValue: 443 },
             { key: 'ENTERPRISE_PROTOCOL', required: false, defaultValue: 'https' },
-            { key: 'USE_SEARCH', required: false, defaultValue: false },
-            { key: 'SEARCH_QUERY', required: false },
             { key: 'WORKSPACE', required: false },
             { key: 'REPO_ROOT_DIRECTORY', required: false }
         ];
diff --git a/td.server/src/env/Github.js b/td.server/src/env/Github.js
index f2147608..37641032 100644
--- a/td.server/src/env/Github.js
+++ b/td.server/src/env/Github.js
@@ -18,6 +18,8 @@ class GithubEnv extends Env {
             { key: 'ENTERPRISE_HOSTNAME', required: false },
             { key: 'ENTERPRISE_PORT', required: false, defaultValue: 443 },
             { key: 'ENTERPRISE_PROTOCOL', required: false, defaultValue: 'https' },
+            { key: 'USE_SEARCH', required: false, defaultValue: false },
+            { key: 'SEARCH_QUERY', required: false },
             { key: 'REPO_ROOT_DIRECTORY', required: false }
         ];
     }
diff --git a/td.server/src/env/Gitlab.js b/td.server/src/env/Gitlab.js
index 51694626..fb09651f 100644
--- a/td.server/src/env/Gitlab.js
+++ b/td.server/src/env/Gitlab.js
@@ -9,14 +9,13 @@ class GitlabEnv extends Env {
         return 'GITLAB_';
     }
 
+    // Note that the actual env var will be prepended with GITLAB_
     get properties () {
         return [
             { key: 'CLIENT_ID', required: false },
             { key: 'CLIENT_SECRET', required: false },
-            { key: 'SCOPE', required: false },
+            { key: 'SCOPE', required: false, defaultValue: 'read_user read_repository' },
             { key: 'HOST', required: false },
-            { key: 'USE_SEARCH', required: false },
-            { key: 'SEARCH_QUERY', required: false },
             { key: 'REDIRECT_URI', required: false },
             { key: 'REPO_ROOT_DIRECTORY', required: false }
         ];


Test patch:
diff --git a/td.server/test/controllers/healthcheck.spec.js b/td.server/test/controllers/healthz.spec.js
similarity index 100%
rename from td.server/test/controllers/healthcheck.spec.js
rename to td.server/test/controllers/healthz.spec.js
diff --git a/td.server/test/env/Bitbucket.spec.js b/td.server/test/env/Bitbucket.spec.js
index 474a5e71..5fd938d5 100644
--- a/td.server/test/env/Bitbucket.spec.js
+++ b/td.server/test/env/Bitbucket.spec.js
@@ -1,7 +1,7 @@
-import Bitbucket from '../../src/env/Bitbucket.js';
-
 import { expect } from 'chai';
+
 import { Env } from '../../src/env/Env.js';
+import Bitbucket from '../../src/env/Bitbucket.js';
 
 describe('env/Bitbucket.js', () => {
     let bitbucketEnv;
@@ -43,10 +43,59 @@ describe('env/Bitbucket.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property SCOPE', () => {
+        const value = bitbucketEnv.properties
+            .find(x => x.key === 'SCOPE')
+            .defaultValue;
+        expect(value).to.equal('repository:read');
+    });
+
+    it('has the optional property ENTERPRISE_HOSTNAME', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'ENTERPRISE_HOSTNAME')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property ENTERPRISE_PORT', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PORT')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property ENTERPRISE_PORT', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PORT')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property ENTERPRISE_PROTOCOL', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PROTOCOL')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property ENTERPRISE_PROTOCOL', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PROTOCOL')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
     it('has the optional property WORKSPACE', () => {
         const isRequired = bitbucketEnv.properties
             .find(x => x.key === 'WORKSPACE')
             .required;
         expect(isRequired).to.be.false;
     });
+
+    it('has the optional property REPO_ROOT_DIRECTORY', () => {
+        const isRequired = bitbucketEnv.properties
+            .find(x => x.key === 'REPO_ROOT_DIRECTORY')
+            .required;
+        expect(isRequired).to.be.false;
+    });
 });
diff --git a/td.server/test/env/Github.spec.js b/td.server/test/env/Github.spec.js
index ef9d6adc..bbb0115e 100644
--- a/td.server/test/env/Github.spec.js
+++ b/td.server/test/env/Github.spec.js
@@ -42,4 +42,74 @@ describe('env/Github.js', () => {
             .required;
         expect(isRequired).to.be.false;
     });
+
+    it('has a default value for property SCOPE', () => {
+        const value = githubEnv.properties
+            .find(x => x.key === 'SCOPE')
+            .defaultValue;
+        expect(value).to.equal('public_repo');
+    });
+
+    it('has the optional property ENTERPRISE_HOSTNAME', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'ENTERPRISE_HOSTNAME')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property ENTERPRISE_PORT', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PORT')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has a default value for property ENTERPRISE_PORT', () => {
+        const value = githubEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PORT')
+            .defaultValue;
+        expect(value).to.equal(443);
+    });
+
+    it('has the optional property ENTERPRISE_PROTOCOL', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PROTOCOL')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has a default value for property ENTERPRISE_PROTOCOL', () => {
+        const value = githubEnv.properties
+            .find(x => x.key === 'ENTERPRISE_PROTOCOL')
+            .defaultValue;
+        expect(value).to.equal('https');
+    });
+
+    it('has the optional property USE_SEARCH', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'USE_SEARCH')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has a default value for property USE_SEARCH', () => {
+        const value = githubEnv.properties
+            .find(x => x.key === 'USE_SEARCH')
+            .defaultValue;
+        expect(value).to.be.false;
+    });
+
+    it('has the optional property SEARCH_QUERY', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'SEARCH_QUERY')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property REPO_ROOT_DIRECTORY', () => {
+        const isRequired = githubEnv.properties
+            .find(x => x.key === 'REPO_ROOT_DIRECTORY')
+            .required;
+        expect(isRequired).to.be.false;
+    });
 });
diff --git a/td.server/test/env/Gitlab.spec.js b/td.server/test/env/Gitlab.spec.js
new file mode 100644
index 00000000..c06e1894
--- /dev/null
+++ b/td.server/test/env/Gitlab.spec.js
@@ -0,0 +1,73 @@
+import { expect } from 'chai';
+
+import { Env } from '../../src/env/Env.js';
+import Gitlab from '../../src/env/Gitlab.js';
+
+describe('env/Gitlab.js', () => {
+    let gitlabEnv;
+
+    beforeEach(() => {
+        gitlabEnv = new Gitlab();
+    });
+
+    it('extends Env', () => {
+        expect(gitlabEnv).is.instanceOf(Env);
+    });
+
+    it('is named bitbucket', () => {
+        expect(gitlabEnv.name).to.eq('Gitlab');
+    });
+
+    it('uses the GITLAB_ prefix', () => {
+        expect(gitlabEnv.prefix).to.eq('GITLAB_');
+    });
+
+    it('has the optional property CLIENT_ID', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'CLIENT_ID')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property CLIENT_SECRET', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'CLIENT_SECRET')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property SCOPE', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'SCOPE')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has a default value for property SCOPE', () => {
+        const value = gitlabEnv.properties
+            .find(x => x.key === 'SCOPE')
+            .defaultValue;
+        expect(value).to.equal('read_user read_repository');
+    });
+
+    it('has the optional property HOST', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'HOST')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property REDIRECT_URI', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'REDIRECT_URI')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has the optional property REPO_ROOT_DIRECTORY', () => {
+        const isRequired = gitlabEnv.properties
+            .find(x => x.key === 'REPO_ROOT_DIRECTORY')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+});
diff --git a/td.server/test/env/ThreatDragon.spec.js b/td.server/test/env/ThreatDragon.spec.js
index 82789f01..1247545d 100644
--- a/td.server/test/env/ThreatDragon.spec.js
+++ b/td.server/test/env/ThreatDragon.spec.js
@@ -29,6 +29,13 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property NODE_ENV', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'NODE_ENV')
+            .defaultValue;
+        expect(value).to.equal('production');
+    });
+
     it('has the optional property PORT', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'PORT')
@@ -36,6 +43,13 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property PORT', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'PORT')
+            .defaultValue;
+        expect(value).to.equal(3000);
+    });
+
     it('has the optional property LOG_MAX_FILE_SIZE', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'LOG_MAX_FILE_SIZE')
@@ -43,6 +57,13 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property LOG_MAX_FILE_SIZE', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'LOG_MAX_FILE_SIZE')
+            .defaultValue;
+        expect(value).to.equal(24);
+    });
+
     it('has the required property LOG_LEVEL', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'LOG_LEVEL')
@@ -50,6 +71,13 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property LOG_LEVEL', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'LOG_LEVEL')
+            .defaultValue;
+        expect(value).to.equal('warn');
+    });
+
     it('has the optional property SERVER_API_PROTOCOL', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'SERVER_API_PROTOCOL')
@@ -57,6 +85,27 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property SERVER_API_PROTOCOL', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'SERVER_API_PROTOCOL')
+            .defaultValue;
+        expect(value).to.equal('https');
+    });
+
+    it('has the optional property REPO_ROOT_DIRECTORY', () => {
+        const isRequired = tdEnv.properties
+            .find(x => x.key === 'REPO_ROOT_DIRECTORY')
+            .required;
+        expect(isRequired).to.be.false;
+    });
+
+    it('has a default value for property REPO_ROOT_DIRECTORY', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'REPO_ROOT_DIRECTORY')
+            .defaultValue;
+        expect(value).to.equal('ThreatDragonModels');
+    });
+
     it('has the optional property REPO_USE_SEARCH', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'REPO_USE_SEARCH')
@@ -64,6 +113,13 @@ describe('env/ThreatDragon.js', () => {
         expect(isRequired).to.be.false;
     });
 
+    it('has a default value for property REPO_USE_SEARCH', () => {
+        const value = tdEnv.properties
+            .find(x => x.key === 'REPO_USE_SEARCH')
+            .defaultValue;
+        expect(value).to.be.false;
+    });
+
     it('has the optional property REPO_SEARCH_QUERY', () => {
         const isRequired = tdEnv.properties
             .find(x => x.key === 'REPO_SEARCH_QUERY')