@spotify/backstage-plugin-soundcheck-backend-module-github 0.8.6 → 0.8.8

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @spotify/backstage-plugin-soundcheck-backend-module-github
2
2
 
3
+ ## 0.8.8
4
+
5
+ ### Patch Changes
6
+
7
+ - Reject unauthenticated GitHub requests in GithubFactCollector, returning collection errors for entities when no token is configured.
8
+ - Fixed double multiplication bug in GitHub rate limit retry calculation that caused collectors to stall for days instead of minutes.
9
+
10
+ ## 0.8.7
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependency `backstage` to `1.49.0`.
15
+ - Updated package to be compatible with zod versions 3 and 4.
16
+ - Updated dependencies
17
+ - Updated dependencies
18
+ - Updated dependencies
19
+ - Updated dependencies
20
+ - Updated dependencies
21
+ - @spotify/backstage-plugin-soundcheck-common@0.22.0
22
+ - @spotify/backstage-plugin-soundcheck-node@0.12.0
23
+
3
24
  ## 0.8.6
4
25
 
5
26
  ### Patch Changes
@@ -1,2 +1,2 @@
1
- "use strict";var F=require("@backstage/catalog-model"),d=require("@backstage/integration"),S=require("@octokit/rest"),t=require("@spotify/backstage-plugin-soundcheck-common"),m=require("@spotify/backstage-plugin-soundcheck-node"),v=require("git-url-parse"),C=require("zod-to-json-schema"),x=require("../extractors/BranchProtectionsFactExtractor.cjs.js"),b=require("../extractors/BranchRulesFactExtractor.cjs.js"),R=require("../extractors/CodeScanningAlertsFactExtractor.cjs.js"),q=require("../extractors/config/GithubFactCollectorSchema.cjs.js"),A=require("../extractors/DependabotAlertsFactExtractor.cjs.js"),D=require("../extractors/ExtractorService.cjs.js"),T=require("../extractors/helper/BranchHelper.cjs.js"),L=require("../extractors/RepositoryDetailsFactExtractor.cjs.js"),P=require("../extractors/RepositoryLanguagesFactExtractor.cjs.js"),U=require("../extractors/SecretScanningAlertsFactExtractor.cjs.js"),k=require("../extractors/SecurityAdvisoriesFactExtractor.cjs.js"),w=require("../extractors/store/GithubExtractorsStore.cjs.js");function y(u){return u&&typeof u=="object"&&"default"in u?u:{default:u}}var O=y(v),B=y(C);const H=new Set(["DependabotAlerts","SecretScanningAlerts","CodeScanningAlerts"]);class n{static ID="github";static DEFAULT_TTL=10080*60*1e3;#r;#a;#i;#e;#t;static create(e,a,r){return new n(e,a,r)}id=n.ID;name="GitHub";description="Collects facts about your GitHub repositories.";constructor(e,a,r){this.#r=a.child({target:this.id}),this.#a=d.ScmIntegrations.fromConfig(e),this.#i=d.DefaultGithubCredentialsProvider.fromIntegrations(this.#a),this.#e=D.ExtractorService.create({logger:a,cache:r.withOptions({defaultTtl:n.DEFAULT_TTL}),branchHelper:T.BranchHelper.create(this.#r,r.withOptions({defaultTtl:n.DEFAULT_TTL})),factories:[x.BranchProtectionsFactExtractor.factory,b.BranchRulesFactExtractor.factory,R.CodeScanningAlertsFactExtractor.factory,A.DependabotAlertsFactExtractor.factory,L.RepositoryDetailsFactExtractor.factory,P.RepositoryLanguagesFactExtractor.factory,U.SecretScanningAlertsFactExtractor.factory,k.SecurityAdvisoriesFactExtractor.factory]}),this.#t=w.GithubExtractorsStore.create(this.#r)}async collect(e,a){const r=a?.factRefs??this.#t.getExtractorConfigs().map(i=>t.getFactRef(this.id,i));return Promise.all(e.map(async i=>{const c=F.stringifyEntityRef(i);try{const s=t.getEntityScmUrl(i),f=O.default(s),E=await this.getOctokit(s);return Promise.all(r.map(async l=>{const g=t.parseFactRef(l,{defaultSource:this.id,defaultScope:t.DEFAULT_SCOPE}),h=this.#t.getExtractorConfig(g.name),p=!!a?.refresh?.map(o=>t.stringifyFactRef(o))?.includes(t.stringifyFactRef(l));return this.#e.extract(h,g.scope,f,E,p).then(o=>{if(o!==void 0)return t.buildFact(c,l,o,H.has(h.type))}).catch(o=>{if(o instanceof m.RateLimitError)throw o;return this.#r.error(`Failed to collect ${t.stringifyFactRef(l)} fact data for ${c} entity: ${o.message??o}`),t.buildCollectionError(c,l,o)})}))}catch(s){return r.map(f=>(this.#r.error(`Failed to collect ${t.stringifyFactRef(f)} fact data for ${c} entity: ${s.message??s}`),t.buildCollectionError(c,f,s)))}})).then(i=>i.flat().filter(c=>!!c))}async getOctokit(e){const{token:a}=await this.#i.getCredentials({url:e}),r=this.#a.github.byUrl(e);return new S.Octokit({auth:a,baseUrl:r?.config.apiBaseUrl})}async getCollectionConfigs(){return t.buildCollectionConfigs(this.id,this.#t.getExtractorConfigs())}async getFactNames(){const e=this.#e.listFactTypes(),a=this.#t.getExtractorConfigs();return e.flatMap(r=>a.filter(i=>i.type===r).map(i=>i.factName??i.type)??r)}async getDataSchema(e){const a=t.parseFactRef(e,{defaultSource:this.id,defaultScope:t.DEFAULT_SCOPE}),r=this.#t.getExtractorConfigs().find(i=>{const c=t.parseFactRef(t.getFactRef(this.id,i));return a.source===c.source&&a.name===c.name});if(r)return this.#e.getDataSchema(r)}async getConfig(){return this.#t.getConfig()}async setConfig(e){this.#t.setConfig(e)}async getConfigSchema(){return JSON.stringify(B.default(q.GithubFactCollectorSchema))}}exports.GithubFactCollector=n;
1
+ "use strict";var F=require("@backstage/catalog-model"),d=require("@backstage/integration"),S=require("@octokit/rest"),t=require("@spotify/backstage-plugin-soundcheck-common"),m=require("@spotify/backstage-plugin-soundcheck-node"),v=require("git-url-parse"),C=require("zod-to-json-schema"),x=require("../extractors/BranchProtectionsFactExtractor.cjs.js"),b=require("../extractors/BranchRulesFactExtractor.cjs.js"),q=require("../extractors/CodeScanningAlertsFactExtractor.cjs.js"),R=require("../extractors/config/GithubFactCollectorSchema.cjs.js"),A=require("../extractors/DependabotAlertsFactExtractor.cjs.js"),D=require("../extractors/ExtractorService.cjs.js"),T=require("../extractors/helper/BranchHelper.cjs.js"),L=require("../extractors/RepositoryDetailsFactExtractor.cjs.js"),w=require("../extractors/RepositoryLanguagesFactExtractor.cjs.js"),P=require("../extractors/SecretScanningAlertsFactExtractor.cjs.js"),U=require("../extractors/SecurityAdvisoriesFactExtractor.cjs.js"),k=require("../extractors/store/GithubExtractorsStore.cjs.js");function y(u){return u&&typeof u=="object"&&"default"in u?u:{default:u}}var B=y(v),O=y(C);const G=new Set(["DependabotAlerts","SecretScanningAlerts","CodeScanningAlerts"]);class n{static ID="github";static DEFAULT_TTL=10080*60*1e3;#r;#a;#i;#e;#t;static create(r,e,a){return new n(r,e,a)}id=n.ID;name="GitHub";description="Collects facts about your GitHub repositories.";constructor(r,e,a){this.#r=e.child({target:this.id}),this.#a=d.ScmIntegrations.fromConfig(r),this.#i=d.DefaultGithubCredentialsProvider.fromIntegrations(this.#a),this.#e=D.ExtractorService.create({logger:e,cache:a.withOptions({defaultTtl:n.DEFAULT_TTL}),branchHelper:T.BranchHelper.create(this.#r,a.withOptions({defaultTtl:n.DEFAULT_TTL})),factories:[x.BranchProtectionsFactExtractor.factory,b.BranchRulesFactExtractor.factory,q.CodeScanningAlertsFactExtractor.factory,A.DependabotAlertsFactExtractor.factory,L.RepositoryDetailsFactExtractor.factory,w.RepositoryLanguagesFactExtractor.factory,P.SecretScanningAlertsFactExtractor.factory,U.SecurityAdvisoriesFactExtractor.factory]}),this.#t=k.GithubExtractorsStore.create(this.#r)}async collect(r,e){const a=e?.factRefs??this.#t.getExtractorConfigs().map(i=>t.getFactRef(this.id,i));return Promise.all(r.map(async i=>{const c=F.stringifyEntityRef(i);try{const s=t.getEntityScmUrl(i),l=B.default(s),p=await this.getOctokit(s);return Promise.all(a.map(async f=>{const g=t.parseFactRef(f,{defaultSource:this.id,defaultScope:t.DEFAULT_SCOPE}),h=this.#t.getExtractorConfig(g.name),E=!!e?.refresh?.map(o=>t.stringifyFactRef(o))?.includes(t.stringifyFactRef(f));return this.#e.extract(h,g.scope,l,p,E).then(o=>{if(o!==void 0)return t.buildFact(c,f,o,G.has(h.type))}).catch(o=>{if(o instanceof m.RateLimitError)throw o;return this.#r.error(`Failed to collect ${t.stringifyFactRef(f)} fact data for ${c} entity: ${o.message??o}`),t.buildCollectionError(c,f,o)})}))}catch(s){return a.map(l=>(this.#r.error(`Failed to collect ${t.stringifyFactRef(l)} fact data for ${c} entity: ${s.message??s}`),t.buildCollectionError(c,l,s)))}})).then(i=>i.flat().filter(c=>!!c))}async getOctokit(r){const{token:e}=await this.#i.getCredentials({url:r});if(!e)throw new Error(`Unauthenticated GitHub requests are not supported. Please configure a GitHub token in your integrations config for ${r}.`);const a=this.#a.github.byUrl(r);return new S.Octokit({auth:e,baseUrl:a?.config.apiBaseUrl})}async getCollectionConfigs(){return t.buildCollectionConfigs(this.id,this.#t.getExtractorConfigs())}async getFactNames(){const r=this.#e.listFactTypes(),e=this.#t.getExtractorConfigs();return r.flatMap(a=>e.filter(i=>i.type===a).map(i=>i.factName??i.type)??a)}async getDataSchema(r){const e=t.parseFactRef(r,{defaultSource:this.id,defaultScope:t.DEFAULT_SCOPE}),a=this.#t.getExtractorConfigs().find(i=>{const c=t.parseFactRef(t.getFactRef(this.id,i));return e.source===c.source&&e.name===c.name});if(a)return this.#e.getDataSchema(a)}async getConfig(){return this.#t.getConfig()}async setConfig(r){this.#t.setConfig(r)}async getConfigSchema(){return JSON.stringify(O.default(R.GithubFactCollectorSchema))}}exports.GithubFactCollector=n;
2
2
  //# sourceMappingURL=GithubFactCollector.cjs.js.map
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("@spotify/backstage-plugin-soundcheck-common"),t=require("zod");const a=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("BranchProtections"),branch:t.z.string().min(1).optional()})).strict(),r=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("BranchRules"),branch:t.z.string().min(1).optional()})).strict(),i=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("CodeScanningAlerts"),toolName:t.z.string().min(1).optional(),state:t.z.enum(["open","closed","dismissed","fixed"]).optional(),severity:t.z.enum(["critical","high","medium","low","warning","note","error"]).optional()})).strict(),c=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("DependabotAlerts"),states:t.z.array(t.z.enum(["auto_dismissed","dismissed","fixed","open"])).optional(),severities:t.z.array(t.z.enum(["low","medium","high","critical"])).optional()})).strict(),s=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("RepositoryDetails")})).strict(),o=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("RepositoryLanguages")})).strict(),n=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("SecretScanningAlerts"),state:t.z.enum(["open","resolved"]).optional(),validities:t.z.array(t.z.enum(["active","inactive","unknown"])).optional()})).strict(),l=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("SecurityAdvisories"),state:t.z.enum(["triage","draft","published","closed"]).optional()})).strict(),m=t.z.union([a,r,i,c,s,o,n,l]),z=e.buildFactCollectorSchema(m);exports.GithubFactCollectorSchema=z;
1
+ "use strict";var e=require("@spotify/backstage-plugin-soundcheck-common"),t=require("zod/v3");const a=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("BranchProtections"),branch:t.z.string().min(1).optional()})).strict(),r=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("BranchRules"),branch:t.z.string().min(1).optional()})).strict(),i=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("CodeScanningAlerts"),toolName:t.z.string().min(1).optional(),state:t.z.enum(["open","closed","dismissed","fixed"]).optional(),severity:t.z.enum(["critical","high","medium","low","warning","note","error"]).optional()})).strict(),c=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("DependabotAlerts"),states:t.z.array(t.z.enum(["auto_dismissed","dismissed","fixed","open"])).optional(),severities:t.z.array(t.z.enum(["low","medium","high","critical"])).optional()})).strict(),s=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("RepositoryDetails")})).strict(),o=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("RepositoryLanguages")})).strict(),n=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("SecretScanningAlerts"),state:t.z.enum(["open","resolved"]).optional(),validities:t.z.array(t.z.enum(["active","inactive","unknown"])).optional()})).strict(),l=e.BaseFactExtractorSchema.merge(t.z.strictObject({type:t.z.literal("SecurityAdvisories"),state:t.z.enum(["triage","draft","published","closed"]).optional()})).strict(),m=t.z.union([a,r,i,c,s,o,n,l]),z=e.buildFactCollectorSchema(m);exports.GithubFactCollectorSchema=z;
2
2
  //# sourceMappingURL=GithubFactCollectorSchema.cjs.js.map
@@ -1,2 +1,2 @@
1
- "use strict";var s=require("@octokit/request-error"),u=require("@spotify/backstage-plugin-soundcheck-node");function d(r){return r instanceof s.RequestError?r.response?`${r.name} ${r.response.status}: ${JSON.stringify(r.response.data)}`:`${r.name} ${r.status}: ${r.message}`:JSON.stringify(r)}function i(r){return r instanceof s.RequestError&&(r.status===429||r.status===403&&(r.response?.headers["retry-after"]!==void 0||r.response?.headers["x-ratelimit-remaining"]==="0"))}function c(r){return r instanceof s.RequestError&&r.status===403&&r.response?.headers["retry-after"]===void 0&&(r.response?.headers["x-ratelimit-remaining"]===void 0||r.response?.headers["x-ratelimit-remaining"]!=="0")}function f(r){return"status"in r&&r.status===304}function m(r){return"status"in r&&r.status===404}function E(r,o){if(i(r)){const e=r;let t=e.response?.headers["retry-after"];if(!t&&e.response?.headers["x-ratelimit-reset"])try{const n=Number.parseInt(e.response.headers["x-ratelimit-reset"],10),a=Math.floor(Date.now()/1e3);t=(n-a+5)*1e3}catch{}throw u.RateLimitError.create(o,r,t?parseInt(t.toString(),10)*1e3:60*1e3)}}exports.buildOctokitErrorMessage=d,exports.handleRateLimitError=E,exports.isForbiddenError=c,exports.isNotFoundError=m,exports.isNotModifiedError=f,exports.isRateLimitError=i;
1
+ "use strict";var s=require("@octokit/request-error"),u=require("@spotify/backstage-plugin-soundcheck-node");function d(r){return r instanceof s.RequestError?r.response?`${r.name} ${r.response.status}: ${JSON.stringify(r.response.data)}`:`${r.name} ${r.status}: ${r.message}`:JSON.stringify(r)}function i(r){return r instanceof s.RequestError&&(r.status===429||r.status===403&&(r.response?.headers["retry-after"]!==void 0||r.response?.headers["x-ratelimit-remaining"]==="0"))}function c(r){return r instanceof s.RequestError&&r.status===403&&r.response?.headers["retry-after"]===void 0&&(r.response?.headers["x-ratelimit-remaining"]===void 0||r.response?.headers["x-ratelimit-remaining"]!=="0")}function f(r){return"status"in r&&r.status===304}function m(r){return"status"in r&&r.status===404}function E(r,o){if(i(r)){const e=r;let t=e.response?.headers["retry-after"];if(!t&&e.response?.headers["x-ratelimit-reset"])try{const n=Number.parseInt(e.response.headers["x-ratelimit-reset"],10),a=Math.floor(Date.now()/1e3);t=n-a+5}catch{}throw u.RateLimitError.create(o,r,t?parseInt(t.toString(),10)*1e3:void 0)}}exports.buildOctokitErrorMessage=d,exports.handleRateLimitError=E,exports.isForbiddenError=c,exports.isNotFoundError=m,exports.isNotModifiedError=f,exports.isRateLimitError=i;
2
2
  //# sourceMappingURL=util.cjs.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spotify/backstage-plugin-soundcheck-backend-module-github",
3
3
  "description": "Soundcheck 3rd party integration with Github",
4
- "version": "0.8.6",
4
+ "version": "0.8.8",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "homepage": "https://backstage.spotify.com",
7
7
  "main": "dist/index.cjs.js",
@@ -27,29 +27,29 @@
27
27
  "postpack": "backstage-cli package postpack"
28
28
  },
29
29
  "devDependencies": {
30
- "@backstage/backend-test-utils": "^1.11.0",
31
- "@backstage/cli": "^0.35.4",
32
- "@spotify/backstage-plugin-soundcheck-backend": "^0.24.0",
30
+ "@backstage/backend-test-utils": "^1.11.1",
31
+ "@backstage/cli": "^0.36.0",
32
+ "@spotify/backstage-plugin-soundcheck-backend": "^0.25.1",
33
33
  "@types/git-url-parse": "^16.0.0",
34
34
  "@types/luxon": "^3.0.1",
35
35
  "supertest": "^7.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@backstage/backend-plugin-api": "^1.7.0",
39
- "@backstage/catalog-model": "^1.7.6",
38
+ "@backstage/backend-plugin-api": "^1.8.0",
39
+ "@backstage/catalog-model": "^1.7.7",
40
40
  "@backstage/config": "^1.3.6",
41
41
  "@backstage/errors": "^1.2.7",
42
- "@backstage/integration": "^1.20.0",
42
+ "@backstage/integration": "^2.0.0",
43
43
  "@backstage/types": "^1.2.2",
44
44
  "@octokit/request-error": "^5.0.0",
45
45
  "@octokit/rest": "^20.0.0",
46
- "@spotify/backstage-plugin-soundcheck-common": "^0.21.0",
47
- "@spotify/backstage-plugin-soundcheck-node": "^0.11.0",
46
+ "@spotify/backstage-plugin-soundcheck-common": "^0.22.0",
47
+ "@spotify/backstage-plugin-soundcheck-node": "^0.12.0",
48
48
  "git-url-parse": "^16.0.0",
49
49
  "lodash": "^4.17.21",
50
50
  "luxon": "^3.1.1",
51
51
  "winston": "^3.2.1",
52
- "zod": "^3.20.0",
52
+ "zod": "^3.25.76 || ^4.0.0",
53
53
  "zod-to-json-schema": "^3.20.2"
54
54
  },
55
55
  "files": [