chore(sentry_webhook): create tests for sentry webhook (#1417)

* Create tests for sentry webhook.

* Add GitHub workflow for new tests.

* Fix package lock files.

* Fix typos.

* Move webhook check up.

* Remove extra `/`.
This commit is contained in:
Sander Bruens 2023-10-06 11:53:56 -04:00 committed by GitHub
parent 7d5dffcdc9
commit 61a8f7d290
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 834 additions and 33 deletions

View file

@ -82,6 +82,29 @@ jobs:
- name: Metrics Server Test
run: npm run action metrics_server/test
sentry-webhook:
name: Sentry Webhook
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: npm
- name: Install NPM Dependencies
run: npm ci
- name: Sentry Webhook Debug Build
run: npm run action sentry_webhook/build
- name: Sentry Webhook Test
run: npm run action sentry_webhook/test
manager-web-test:
name: Manager Web Test
runs-on: ubuntu-latest

565
package-lock.json generated
View file

@ -675,6 +675,102 @@
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@isaacs/cliui/node_modules/strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.4",
"dev": true,
@ -806,6 +902,16 @@
"node": ">= 8"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"optional": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@polymer/app-layout": {
"version": "3.1.0",
"license": "BSD-3-Clause",
@ -6448,6 +6554,12 @@
"node": ">=0.10.0"
}
},
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"license": "MIT",
@ -8768,6 +8880,34 @@
"node": ">=0.10.0"
}
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/foreground-child/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/forever-agent": {
"version": "0.6.1",
"license": "Apache-2.0",
@ -11227,6 +11367,24 @@
"node": ">= 4"
}
},
"node_modules/jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dev": true,
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
"optionalDependencies": {
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/jake": {
"version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
@ -13855,6 +14013,40 @@
"node": ">=0.10.0"
}
},
"node_modules/path-scurry": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
"dev": true,
"dependencies": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
"integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
"dev": true,
"engines": {
"node": "14 || >=16.14"
}
},
"node_modules/path-scurry/node_modules/minipass": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"license": "MIT"
@ -17337,6 +17529,30 @@
"node": ">=8"
}
},
"node_modules/string-width-cjs": {
"name": "string-width",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/string-width/node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -17385,6 +17601,19 @@
"node": ">=8"
}
},
"node_modules/strip-ansi-cjs": {
"name": "strip-ansi",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-bom": {
"version": "2.0.0",
"dev": true,
@ -19885,6 +20114,24 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi-cjs": {
"name": "wrap-ansi",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"license": "ISC"
@ -20052,7 +20299,9 @@
"license": "Apache",
"devDependencies": {
"@sentry/types": "^4.4.1",
"@types/express": "^4.17.12"
"@types/express": "^4.17.12",
"@types/jasmine": "^5.1.0",
"jasmine": "^5.1.0"
}
},
"src/sentry_webhook/node_modules/@sentry/types": {
@ -20063,9 +20312,89 @@
"node": ">=6"
}
},
"src/sentry_webhook/node_modules/@types/jasmine": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.0.tgz",
"integrity": "sha512-XOV0KsqXNX2gUSqk05RWeolIMgaAQ7+l/ozOBoQ8NGwLg+E7J9vgagODtNgfim4jCzEUP0oJ3gnXeC+Zv+Xi1A==",
"dev": true
},
"src/sentry_webhook/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"src/sentry_webhook/node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
"minimatch": "^9.0.1",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
"path-scurry": "^1.10.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"src/sentry_webhook/node_modules/jasmine": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.1.0.tgz",
"integrity": "sha512-prmJlC1dbLhti4nE4XAPDWmfJesYO15sjGXVp7Cs7Ym5I9Xtwa/hUHxxJXjnpfLO72+ySttA0Ztf8g/RiVnUKw==",
"dev": true,
"dependencies": {
"glob": "^10.2.2",
"jasmine-core": "~5.1.0"
},
"bin": {
"jasmine": "bin/jasmine.js"
}
},
"src/sentry_webhook/node_modules/jasmine-core": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.1.tgz",
"integrity": "sha512-UrzO3fL7nnxlQXlvTynNAenL+21oUQRlzqQFsA2U11ryb4+NLOCOePZ70PTojEaUKhiFugh7dG0Q+I58xlPdWg==",
"dev": true
},
"src/sentry_webhook/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"src/sentry_webhook/node_modules/minipass": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"src/server_manager": {
"name": "outline-manager",
"version": "1.14.0",
"version": "0.0.0-debug",
"license": "Apache",
"dependencies": {
"@polymer/app-layout": "^3.0.0",
@ -20967,6 +21296,71 @@
"version": "1.2.1",
"dev": true
},
"@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
"dev": true,
"requires": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
"strip-ansi": "^7.0.1",
"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
"wrap-ansi": "^8.1.0",
"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"dev": true
},
"ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
"dev": true
},
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
"dev": true,
"requires": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
"strip-ansi": "^7.0.1"
}
},
"strip-ansi": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
"dev": true,
"requires": {
"ansi-regex": "^6.0.1"
}
},
"wrap-ansi": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
"dev": true,
"requires": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
"strip-ansi": "^7.0.1"
}
}
}
},
"@leichtgewicht/ip-codec": {
"version": "2.0.4",
"dev": true
@ -21059,6 +21453,13 @@
"fastq": "^1.6.0"
}
},
"@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
"dev": true,
"optional": true
},
"@polymer/app-layout": {
"version": "3.1.0",
"requires": {
@ -25173,6 +25574,12 @@
}
}
},
"eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"ecc-jsbn": {
"version": "0.1.2",
"requires": {
@ -26818,6 +27225,24 @@
"for-in": "^1.0.1"
}
},
"foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.0",
"signal-exit": "^4.0.1"
},
"dependencies": {
"signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true
}
}
},
"forever-agent": {
"version": "0.6.1"
},
@ -28453,6 +28878,16 @@
"is-object": "^1.0.1"
}
},
"jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
"integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dev": true,
"requires": {
"@isaacs/cliui": "^8.0.2",
"@pkgjs/parseargs": "^0.11.0"
}
},
"jake": {
"version": "10.8.5",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz",
@ -30668,6 +31103,30 @@
"version": "0.1.2",
"dev": true
},
"path-scurry": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
"dev": true,
"requires": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"dependencies": {
"lru-cache": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
"integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
"dev": true
},
"minipass": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true
}
}
},
"path-to-regexp": {
"version": "0.1.7"
},
@ -32375,12 +32834,73 @@
"version": "file:src/sentry_webhook",
"requires": {
"@sentry/types": "^4.4.1",
"@types/express": "^4.17.12"
"@types/express": "^4.17.12",
"@types/jasmine": "^5.1.0",
"jasmine": "^5.1.0"
},
"dependencies": {
"@sentry/types": {
"version": "4.5.3",
"dev": true
},
"@types/jasmine": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.0.tgz",
"integrity": "sha512-XOV0KsqXNX2gUSqk05RWeolIMgaAQ7+l/ozOBoQ8NGwLg+E7J9vgagODtNgfim4jCzEUP0oJ3gnXeC+Zv+Xi1A==",
"dev": true
},
"brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0"
}
},
"glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dev": true,
"requires": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
"minimatch": "^9.0.1",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
"path-scurry": "^1.10.1"
}
},
"jasmine": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.1.0.tgz",
"integrity": "sha512-prmJlC1dbLhti4nE4XAPDWmfJesYO15sjGXVp7Cs7Ym5I9Xtwa/hUHxxJXjnpfLO72+ySttA0Ztf8g/RiVnUKw==",
"dev": true,
"requires": {
"glob": "^10.2.2",
"jasmine-core": "~5.1.0"
}
},
"jasmine-core": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.1.tgz",
"integrity": "sha512-UrzO3fL7nnxlQXlvTynNAenL+21oUQRlzqQFsA2U11ryb4+NLOCOePZ70PTojEaUKhiFugh7dG0Q+I58xlPdWg==",
"dev": true
},
"minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dev": true,
"requires": {
"brace-expansion": "^2.0.1"
}
},
"minipass": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
"dev": true
}
}
},
@ -33130,6 +33650,25 @@
}
}
},
"string-width-cjs": {
"version": "npm:string-width@4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"dependencies": {
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
}
}
},
"string.prototype.trimend": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
@ -33159,6 +33698,15 @@
"ansi-regex": "^5.0.1"
}
},
"strip-ansi-cjs": {
"version": "npm:strip-ansi@6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
},
"strip-bom": {
"version": "2.0.0",
"dev": true,
@ -34890,6 +35438,17 @@
"strip-ansi": "^6.0.0"
}
},
"wrap-ansi-cjs": {
"version": "npm:wrap-ansi@7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"wrappy": {
"version": "1.0.2"
},

View file

@ -48,7 +48,7 @@ function run_action() {
echo -e "${old_indent}${STYLE_BOLD_WHITE}[Running ${action}]${STYLE_RESET}"
shift
"${ROOT_DIR}/src/${action}.action.sh" "$@"
"${ROOT_DIR}src/${action}.action.sh" "$@"
local -ir status="$?"
if (( status == 0 )); then

View file

@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
tsc -p "$(dirname "$0")"
tsc --project "${ROOT_DIR}"src/sentry_webhook/tsconfig.prod.json

View file

@ -0,0 +1,9 @@
import type {SentryEvent as SentryEventBase} from '@sentry/types';
// Although SentryEvent.tags is declared as an index signature object, it is actually an array of
// arrays i.e. [['key0', 'value0'], ['key1', 'value1']].
export type Tags = null | [string, string][];
export interface SentryEvent extends Omit<SentryEventBase, 'tags'> {
tags?: Tags | null;
}

View file

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import * as sentry from '@sentry/types';
import * as express from 'express';
import {
postSentryEventToSalesforce,
shouldPostEventToSalesforce,
} from './post_sentry_event_to_salesforce';
import {SentryEvent} from './event';
exports.postSentryEventToSalesforce = (req: express.Request, res: express.Response<string>) => {
if (req.method !== 'POST') {
@ -28,7 +28,7 @@ exports.postSentryEventToSalesforce = (req: express.Request, res: express.Respon
return res.status(400).send('Missing request body');
}
const sentryEvent: sentry.SentryEvent = req.body.event;
const sentryEvent: SentryEvent = req.body.event;
if (!sentryEvent) {
return res.status(400).send('Missing Sentry event');
}

View file

@ -0,0 +1,49 @@
/* eslint-disable @typescript-eslint/no-var-requires */
// Copyright 2020 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const {makeConfig} = require('./test.webpack.js');
process.env.CHROMIUM_BIN = require('puppeteer').executablePath();
const baseConfig = makeConfig({
defaultMode: 'development',
});
const TEST_PATTERNS = ['**/*.spec.ts'];
let preprocessors = {};
for (const pattern of TEST_PATTERNS) {
preprocessors[pattern] = ['webpack'];
}
module.exports = function (config) {
config.set({
frameworks: ['jasmine'],
files: TEST_PATTERNS,
preprocessors,
reporters: ['progress'],
colors: true,
logLevel: config.LOG_INFO,
browsers: ['ChromiumHeadless'],
restartOnFileChange: true,
singleRun: true,
concurrency: Infinity,
webpack: {
module: baseConfig.module,
resolve: baseConfig.resolve,
plugins: baseConfig.plugins,
mode: baseConfig.mode,
},
});
};

View file

@ -5,9 +5,10 @@
"description": "Outline Sentry Webhook",
"author": "Outline",
"license": "Apache",
"dependencies": {},
"devDependencies": {
"@sentry/types": "^4.4.1",
"@types/express": "^4.17.12"
"@types/express": "^4.17.12",
"@types/jasmine": "^5.1.0",
"jasmine": "^5.1.0"
}
}

View file

@ -0,0 +1,117 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {ClientRequest} from 'http';
import * as https from 'https';
import {postSentryEventToSalesforce} from './post_sentry_event_to_salesforce';
import {SentryEvent} from './event';
// NOTE: Jasmine's `toHaveBeenCalledWith` infers parameters for overloads
// incorrectly. See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42455.
function expectToHaveBeenCalledWith(spy: jasmine.Spy, expected: unknown) {
expect(spy.calls.argsFor(0)[0]).toEqual(expected);
}
const BASIC_EVENT: SentryEvent = {
user: {email: 'foo@bar.com'},
message: 'my message',
};
describe('postSentryEventToSalesforce', () => {
let mockRequest: jasmine.SpyObj<ClientRequest>;
let requestSpy: jasmine.Spy;
beforeEach(() => {
mockRequest = jasmine.createSpyObj('request', ['on', 'write', 'end']);
requestSpy = spyOn(https, 'request').and.returnValue(mockRequest);
});
it('sends the correct data for a basic prod event', () => {
postSentryEventToSalesforce(BASIC_EVENT, 'outline-clients');
const expectedOptions = {
host: 'webto.salesforce.com',
path: '/servlet/servlet.WebToCase',
protocol: 'https:',
method: 'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
};
expectToHaveBeenCalledWith(requestSpy, expectedOptions);
expectToHaveBeenCalledWith(
mockRequest.write,
'orgid=00D0b000000BrsN' +
'&recordType=0120b0000006e8i' +
'&email=foo%40bar.com' +
'&00N0b00000BqOA4=' +
'&description=my%20message' +
'&type=Outline%20client'
);
expect(mockRequest.end).toHaveBeenCalled();
});
it('sends the correct data for a basic dev event', () => {
postSentryEventToSalesforce(BASIC_EVENT, 'outline-clients-dev');
const expectedOptions = {
host: 'google-jigsaw--uat.my.salesforce.com',
path: '/servlet/servlet.WebToCase',
protocol: 'https:',
method: 'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
};
expectToHaveBeenCalledWith(requestSpy, expectedOptions);
expectToHaveBeenCalledWith(
mockRequest.write,
'orgid=00D3F000000DDDH' +
'&recordType=0123F000000MWTS' +
'&email=foo%40bar.com' +
'&00N3F000002Rqhq=' +
'&description=my%20message' +
'&type=Outline%20client'
);
expect(mockRequest.end).toHaveBeenCalled();
});
it('sends correctly converted tags', () => {
const event: SentryEvent = {
user: {email: 'foo@bar.com'},
message: 'my message',
tags: [
['category', 'test category'],
['os.name', 'test os'],
['sentry:release', 'test version'],
['unknown:tag', 'foo'],
],
};
postSentryEventToSalesforce(event, 'outline-clients');
expectToHaveBeenCalledWith(
mockRequest.write,
'orgid=00D0b000000BrsN' +
'&recordType=0120b0000006e8i' +
'&email=foo%40bar.com' +
'&00N0b00000BqOA4=' +
'&description=my%20message' +
'&type=Outline%20client' +
'&00N0b00000BqOA2=test%20category' +
'&00N0b00000BqOfW=test%20os' +
'&00N0b00000BqOfR=test%20version'
);
expect(mockRequest.end).toHaveBeenCalled();
});
});

View file

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import * as sentry from '@sentry/types';
import * as https from 'https';
import {SentryEvent} from './event';
// Defines the Salesforce form field names.
interface SalesforceFormFields {
@ -73,16 +73,13 @@ const SALESFORCE_FORM_VALUES_PROD: SalesforceFormValues = {
// Returns whether a Sentry event should be sent to Salesforce by checking that it contains an
// email address.
export function shouldPostEventToSalesforce(event: sentry.SentryEvent): boolean {
return !!event.user && !!event.user.email && event.user.email !== "[undefined]";
export function shouldPostEventToSalesforce(event: SentryEvent): boolean {
return !!event.user && !!event.user.email && event.user.email !== '[undefined]';
}
// Posts a Sentry event to Salesforce using predefined form data. Assumes
// `shouldPostEventToSalesforce` has returned true for `event`.
export function postSentryEventToSalesforce(
event: sentry.SentryEvent,
project: string
): Promise<void> {
export function postSentryEventToSalesforce(event: SentryEvent, project: string): Promise<void> {
return new Promise((resolve, reject) => {
// Sentry development projects are marked with 'dev', i.e. outline-client-dev.
const isProd = project.indexOf('-dev') === -1;
@ -129,7 +126,7 @@ export function postSentryEventToSalesforce(
function getSalesforceFormData(
formFields: SalesforceFormFields,
formValues: SalesforceFormValues,
event: sentry.SentryEvent,
event: SentryEvent,
email: string,
isClient: boolean,
project: string
@ -142,7 +139,7 @@ function getSalesforceFormData(
form.push(encodeFormData(formFields.description, event.message));
form.push(encodeFormData(formFields.type, isClient ? 'Outline client' : 'Outline manager'));
if (event.tags) {
const tags = getTagsMap(event.tags);
const tags = new Map<string, string>(event.tags);
form.push(encodeFormData(formFields.category, tags.get('category')));
form.push(encodeFormData(formFields.os, tags.get('os.name')));
form.push(encodeFormData(formFields.version, tags.get('sentry:release')));
@ -157,21 +154,6 @@ function encodeFormData(field: string, value?: string) {
return `${encodeURIComponent(field)}=${encodeURIComponent(value || '')}`;
}
// Although SentryEvent.tags is declared as an index signature object, it is actually an array of
// arrays i.e. [['key0': 'value0'], ['key1': 'value1']]. Converts the tags to a Map of strings.
function getTagsMap(tags: {[key: string]: string}) {
const tagsMap = new Map<string, string>();
for (const i of Object.keys(tags)) {
try {
const tagEntry = tags[i];
tagsMap.set(tagEntry[0], tagEntry[1]);
} catch (e) {
console.error('Failed to process tag entry');
}
}
return tagsMap;
}
function getSentryEventUrl(project: string, eventId?: string) {
if (!eventId) {
return '';

View file

@ -0,0 +1,26 @@
#!/bin/bash -eu
#
# Copyright 2023 The Outline Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
readonly TEST_DIR="${BUILD_DIR}/js/sentry_webhook/"
rm -rf "${TEST_DIR}"
# Use commonjs modules, jasmine runs in node.
tsc -p "${ROOT_DIR}/src/sentry_webhook" --outDir "${TEST_DIR}" --module commonjs
jasmine --config="${ROOT_DIR}/jasmine.json"
karma start "${ROOT_DIR}/src/sentry_webhook/karma.conf.js"
rm -rf "${TEST_DIR}"

View file

@ -0,0 +1,31 @@
// Copyright 2023 The Outline Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
exports.makeConfig = (options) => {
return {
mode: options.defaultMode,
target: options.target,
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.ts(x)?$/,
exclude: /node_modules/,
use: ['ts-loader'],
},
],
},
resolve: {extensions: ['.tsx', '.ts', '.js']},
};
};

View file

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.spec.ts"]
}