create-qpq-app 0.1.17 → 0.1.18

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.
Files changed (133) hide show
  1. package/package.json +3 -3
  2. package/template/apps/qpqjs/packages/constants/src/QpqjsServiceEnum.ts +2 -0
  3. package/template/apps/qpqjs/packages/constants/src/index.ts +1 -0
  4. package/template/apps/qpqjs/packages/constants/src/smokeProbe.ts +13 -0
  5. package/template/apps/qpqjs/services/test/config/package.json +22 -0
  6. package/template/apps/qpqjs/services/test/config/src/index.ts +2 -0
  7. package/template/apps/qpqjs/services/test/config/tsconfig.json +18 -0
  8. package/template/apps/qpqjs/services/test/config/tsconfig.lib.json +19 -0
  9. package/template/apps/qpqjs/services/test/models/package.json +22 -0
  10. package/template/apps/qpqjs/services/test/models/src/SmokeProbeRecord.ts +8 -0
  11. package/template/apps/qpqjs/services/test/models/src/SmokeRun.ts +14 -0
  12. package/template/apps/qpqjs/services/test/models/src/SmokeRunStatus.ts +5 -0
  13. package/template/apps/qpqjs/services/test/models/src/SmokeRunSummary.ts +8 -0
  14. package/template/apps/qpqjs/services/test/models/src/SmokeRunWithSummary.ts +7 -0
  15. package/template/apps/qpqjs/services/test/models/src/SmokeTestResult.ts +15 -0
  16. package/template/apps/qpqjs/services/test/models/src/SmokeTestStatus.ts +6 -0
  17. package/template/apps/qpqjs/services/test/models/src/index.ts +7 -0
  18. package/template/apps/qpqjs/services/test/models/tsconfig.json +18 -0
  19. package/template/apps/qpqjs/services/test/models/tsconfig.lib.json +19 -0
  20. package/template/apps/qpqjs/services/test/service/package.json +9 -0
  21. package/template/apps/qpqjs/services/test/service/src/infrastructure.ts +19 -0
  22. package/template/apps/qpqjs/services/test/service/src/smoke/config/defineSmoke.ts +102 -0
  23. package/template/apps/qpqjs/services/test/service/src/smoke/config/index.ts +1 -0
  24. package/template/apps/qpqjs/services/test/service/src/smoke/constants/SMOKE_RUNS_STORE.ts +2 -0
  25. package/template/apps/qpqjs/services/test/service/src/smoke/constants/githubOidc.ts +19 -0
  26. package/template/apps/qpqjs/services/test/service/src/smoke/constants/index.ts +4 -0
  27. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeProbe.ts +14 -0
  28. package/template/apps/qpqjs/services/test/service/src/smoke/constants/smokeRunQueue.ts +6 -0
  29. package/template/apps/qpqjs/services/test/service/src/smoke/controller/askGetSmokeRun.ts +27 -0
  30. package/template/apps/qpqjs/services/test/service/src/smoke/controller/askRunSmokeTests.ts +19 -0
  31. package/template/apps/qpqjs/services/test/service/src/smoke/controller/index.ts +2 -0
  32. package/template/apps/qpqjs/services/test/service/src/smoke/data/askGetSmokeRunById.ts +16 -0
  33. package/template/apps/qpqjs/services/test/service/src/smoke/data/askSaveSmokeRun.ts +9 -0
  34. package/template/apps/qpqjs/services/test/service/src/smoke/data/index.ts +2 -0
  35. package/template/apps/qpqjs/services/test/service/src/smoke/index.ts +9 -0
  36. package/template/apps/qpqjs/services/test/service/src/smoke/logic/github/index.ts +1 -0
  37. package/template/apps/qpqjs/services/test/service/src/smoke/logic/github/verifyGithubOidcToken.ts +105 -0
  38. package/template/apps/qpqjs/services/test/service/src/smoke/logic/index.ts +2 -0
  39. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askExecuteSmokeRun.ts +81 -0
  40. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askFindSmokeRun.ts +11 -0
  41. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/askStartSmokeRun.ts +62 -0
  42. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/index.ts +4 -0
  43. package/template/apps/qpqjs/services/test/service/src/smoke/logic/smokeRun/summarizeSmokeRun.ts +25 -0
  44. package/template/apps/qpqjs/services/test/service/src/smoke/models/GithubOidcClaims.ts +11 -0
  45. package/template/apps/qpqjs/services/test/service/src/smoke/models/SmokeProbeEventQueueEvent.ts +9 -0
  46. package/template/apps/qpqjs/services/test/service/src/smoke/models/SmokeRunRequestedQueueEvent.ts +9 -0
  47. package/template/apps/qpqjs/services/test/service/src/smoke/models/index.ts +3 -0
  48. package/template/apps/qpqjs/services/test/service/src/smoke/processors/github/getGithubOidcAuthProcessors.ts +67 -0
  49. package/template/apps/qpqjs/services/test/service/src/smoke/processors/github/index.ts +1 -0
  50. package/template/apps/qpqjs/services/test/service/src/smoke/processors/index.ts +1 -0
  51. package/template/apps/qpqjs/services/test/service/src/smoke/queue/index.ts +2 -0
  52. package/template/apps/qpqjs/services/test/service/src/smoke/queue/onSmokeProbeEvent.ts +27 -0
  53. package/template/apps/qpqjs/services/test/service/src/smoke/queue/onSmokeRunRequested.ts +15 -0
  54. package/template/apps/qpqjs/services/test/service/src/smoke/tests/SmokeTestDefinition.ts +8 -0
  55. package/template/apps/qpqjs/services/test/service/src/smoke/tests/askSmokeAssert.ts +12 -0
  56. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/askRunCrossServiceKeyValueStoreTest.ts +47 -0
  57. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/askRunCrossServiceStorageDriveTest.ts +46 -0
  58. package/template/apps/qpqjs/services/test/service/src/smoke/tests/crossService/index.ts +2 -0
  59. package/template/apps/qpqjs/services/test/service/src/smoke/tests/eventBus/askRunEventBusTest.ts +57 -0
  60. package/template/apps/qpqjs/services/test/service/src/smoke/tests/eventBus/index.ts +1 -0
  61. package/template/apps/qpqjs/services/test/service/src/smoke/tests/index.ts +10 -0
  62. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/askRunKeyValueStoreTest.ts +71 -0
  63. package/template/apps/qpqjs/services/test/service/src/smoke/tests/keyValueStore/index.ts +1 -0
  64. package/template/apps/qpqjs/services/test/service/src/smoke/tests/noop/askRunNoopTest.ts +7 -0
  65. package/template/apps/qpqjs/services/test/service/src/smoke/tests/noop/index.ts +1 -0
  66. package/template/apps/qpqjs/services/test/service/src/smoke/tests/parameter/askRunParameterTest.ts +27 -0
  67. package/template/apps/qpqjs/services/test/service/src/smoke/tests/parameter/index.ts +1 -0
  68. package/template/apps/qpqjs/services/test/service/src/smoke/tests/secret/askRunSecretTest.ts +16 -0
  69. package/template/apps/qpqjs/services/test/service/src/smoke/tests/secret/index.ts +1 -0
  70. package/template/apps/qpqjs/services/test/service/src/smoke/tests/smokeTestRegistry.ts +29 -0
  71. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/askRunStorageDriveTest.ts +46 -0
  72. package/template/apps/qpqjs/services/test/service/src/smoke/tests/storageDrive/index.ts +1 -0
  73. package/template/apps/qpqjs/services/test/service/tsconfig.app.json +17 -0
  74. package/template/apps/qpqjs/services/test/service/tsconfig.json +8 -0
  75. package/template/apps/qpqjs/services/test/service-utils/package.json +22 -0
  76. package/template/apps/qpqjs/services/test/service-utils/src/index.ts +2 -0
  77. package/template/apps/qpqjs/services/test/service-utils/tsconfig.json +18 -0
  78. package/template/apps/qpqjs/services/test/service-utils/tsconfig.lib.json +19 -0
  79. package/template/apps/qpqjs/services/test/shared-logic/package.json +22 -0
  80. package/template/apps/qpqjs/services/test/shared-logic/src/index.ts +2 -0
  81. package/template/apps/qpqjs/services/test/shared-logic/tsconfig.json +18 -0
  82. package/template/apps/qpqjs/services/test/shared-logic/tsconfig.lib.json +19 -0
  83. package/template/apps/qpqjs/services/test/x-logic/package.json +22 -0
  84. package/template/apps/qpqjs/services/test/x-logic/src/index.ts +2 -0
  85. package/template/apps/qpqjs/services/test/x-logic/tsconfig.json +18 -0
  86. package/template/apps/qpqjs/services/test/x-logic/tsconfig.lib.json +19 -0
  87. package/template/apps/qpqjs/services/test/x-models/package.json +22 -0
  88. package/template/apps/qpqjs/services/test/x-models/src/index.ts +2 -0
  89. package/template/apps/qpqjs/services/test/x-models/tsconfig.json +18 -0
  90. package/template/apps/qpqjs/services/test/x-models/tsconfig.lib.json +19 -0
  91. package/template/apps/qpqjs/services/testa/config/package.json +22 -0
  92. package/template/apps/qpqjs/services/testa/config/src/index.ts +2 -0
  93. package/template/apps/qpqjs/services/testa/config/tsconfig.json +18 -0
  94. package/template/apps/qpqjs/services/testa/config/tsconfig.lib.json +19 -0
  95. package/template/apps/qpqjs/services/testa/models/package.json +22 -0
  96. package/template/apps/qpqjs/services/testa/models/src/CrossServiceKeyValueStoreProbeResult.ts +5 -0
  97. package/template/apps/qpqjs/services/testa/models/src/CrossServiceProbePayload.ts +4 -0
  98. package/template/apps/qpqjs/services/testa/models/src/CrossServiceStorageDriveProbeResult.ts +6 -0
  99. package/template/apps/qpqjs/services/testa/models/src/index.ts +3 -0
  100. package/template/apps/qpqjs/services/testa/models/tsconfig.json +18 -0
  101. package/template/apps/qpqjs/services/testa/models/tsconfig.lib.json +19 -0
  102. package/template/apps/qpqjs/services/testa/service/package.json +9 -0
  103. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/defineCrossServiceProbe.ts +52 -0
  104. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/config/index.ts +1 -0
  105. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/index.ts +1 -0
  106. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/index.ts +2 -0
  107. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/smokeCrossServiceKeyValueStoreProbe.ts +16 -0
  108. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/entry/serviceFunction/smokeCrossServiceStorageDriveProbe.ts +16 -0
  109. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/index.ts +3 -0
  110. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/askProbeForeignKeyValueStore.ts +39 -0
  111. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/askProbeForeignStorageDrive.ts +30 -0
  112. package/template/apps/qpqjs/services/testa/service/src/crossServiceProbe/logic/index.ts +2 -0
  113. package/template/apps/qpqjs/services/testa/service/src/infrastructure.ts +22 -0
  114. package/template/apps/qpqjs/services/testa/service/tsconfig.app.json +17 -0
  115. package/template/apps/qpqjs/services/testa/service/tsconfig.json +8 -0
  116. package/template/apps/qpqjs/services/testa/service-utils/package.json +22 -0
  117. package/template/apps/qpqjs/services/testa/service-utils/src/index.ts +2 -0
  118. package/template/apps/qpqjs/services/testa/service-utils/tsconfig.json +18 -0
  119. package/template/apps/qpqjs/services/testa/service-utils/tsconfig.lib.json +19 -0
  120. package/template/apps/qpqjs/services/testa/shared-logic/package.json +22 -0
  121. package/template/apps/qpqjs/services/testa/shared-logic/src/index.ts +2 -0
  122. package/template/apps/qpqjs/services/testa/shared-logic/tsconfig.json +18 -0
  123. package/template/apps/qpqjs/services/testa/shared-logic/tsconfig.lib.json +19 -0
  124. package/template/apps/qpqjs/services/testa/x-logic/package.json +22 -0
  125. package/template/apps/qpqjs/services/testa/x-logic/src/index.ts +2 -0
  126. package/template/apps/qpqjs/services/testa/x-logic/tsconfig.json +18 -0
  127. package/template/apps/qpqjs/services/testa/x-logic/tsconfig.lib.json +19 -0
  128. package/template/apps/qpqjs/services/testa/x-models/package.json +22 -0
  129. package/template/apps/qpqjs/services/testa/x-models/src/index.ts +2 -0
  130. package/template/apps/qpqjs/services/testa/x-models/tsconfig.json +18 -0
  131. package/template/apps/qpqjs/services/testa/x-models/tsconfig.lib.json +19 -0
  132. package/template/docusaurus/docs/actions/webserver/route-auth-validation/ask-route-auth-validation-decode.md +21 -10
  133. package/template/scripts/deployedSmoke.mjs +134 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qpq-app",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "Scaffold a new quidproquo app: npx create-qpq-app my-app",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -26,7 +26,7 @@
26
26
  "build:esm": "tsc -p tsconfig.esm.json",
27
27
  "build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/createQpqApp.js', 0o755)\"",
28
28
  "snapshot-template": "node ./scripts/snapshotTemplate.mjs",
29
- "smoke-test": "node ./scripts/smokeTest.mjs",
29
+ "scaffold-test": "node ./scripts/scaffoldTest.mjs",
30
30
  "prepack": "npm run snapshot-template",
31
31
  "lint": "npx eslint .",
32
32
  "lint:fix": "npx eslint . --fix",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/node": "^22.13.13",
58
- "quidproquo-tsconfig": "0.1.17"
58
+ "quidproquo-tsconfig": "0.1.18"
59
59
  },
60
60
  "bin": {
61
61
  "create-qpq-app": "./lib/commonjs/bin/createQpqApp.js"
@@ -3,6 +3,8 @@ export enum QpqjsServiceEnum {
3
3
  Auth = 'auth',
4
4
  Design = 'design',
5
5
  Shell = 'shell',
6
+ Test = 'test',
7
+ TestA = 'testa',
6
8
  }
7
9
 
8
10
  export type QpqjsServiceEnumValues = `${QpqjsServiceEnum}`;
@@ -1,3 +1,4 @@
1
1
  export * from './domain';
2
2
  export * from './QpqjsServiceEnum';
3
+ export * from './smokeProbe';
3
4
  export * from './userDirectory';
@@ -0,0 +1,13 @@
1
+ // Smoke probe resources owned by the test service and reached cross-service
2
+ // by testa (which declares them with owner: { module: test }). App-level
3
+ // because both services must agree on the names.
4
+ export const SMOKE_PROBE_STORE = 'smokeProbe';
5
+ // Lowercase with a hyphen: this becomes an S3 bucket name, which must be lowercase.
6
+ export const SMOKE_PROBE_DRIVE = 'smoke-probe';
7
+
8
+ // The testa service functions the cross-service smoke tests invoke, one per
9
+ // foreign grant (the store and the drive are separate IAM statements).
10
+ export const SMOKE_CROSS_SERVICE_KEY_VALUE_STORE_PROBE_FUNCTION_NAME =
11
+ 'crossKvsProbe';
12
+ export const SMOKE_CROSS_SERVICE_STORAGE_DRIVE_PROBE_FUNCTION_NAME =
13
+ 'crossDriveProbe';
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@qpqjs/test-config",
3
+ "version": "0.0.1",
4
+ "dependencies": {
5
+ "tslib": "^2.3.0"
6
+ },
7
+ "type": "commonjs",
8
+ "main": "./dist/src/index.js",
9
+ "typings": "./dist/src/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/src/index.d.ts",
13
+ "default": "./dist/src/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -b"
21
+ }
22
+ }
@@ -0,0 +1,2 @@
1
+ // Intentionally empty — noop placeholder package for the qpqjs app.
2
+ export {};
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "../../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "noImplicitOverride": true,
8
+ "noImplicitReturns": true,
9
+ "noFallthroughCasesInSwitch": true
10
+ },
11
+ "files": [],
12
+ "include": [],
13
+ "references": [
14
+ {
15
+ "path": "./tsconfig.lib.json"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "declaration": true,
6
+ "types": [
7
+ "node"
8
+ ],
9
+ "rootDir": ".",
10
+ "composite": true
11
+ },
12
+ "include": [
13
+ "src/**/*.ts"
14
+ ],
15
+ "exclude": [
16
+ "jest.config.ts",
17
+ "src/**/*.spec.ts"
18
+ ]
19
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@qpqjs/test-models",
3
+ "version": "0.0.1",
4
+ "dependencies": {
5
+ "tslib": "^2.3.0"
6
+ },
7
+ "type": "commonjs",
8
+ "main": "./dist/src/index.js",
9
+ "typings": "./dist/src/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/src/index.d.ts",
13
+ "default": "./dist/src/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -b"
21
+ }
22
+ }
@@ -0,0 +1,8 @@
1
+ // A row in the smokeProbe store. `category` is the store's GSI partition key,
2
+ // so querying by it proves index access under the tag-conditioned grant.
3
+ // External: testa writes these rows cross-service.
4
+ export type SmokeProbeRecord = {
5
+ probeId: string;
6
+ category: string;
7
+ value: number;
8
+ };
@@ -0,0 +1,14 @@
1
+ import { Nullable } from 'quidproquo';
2
+
3
+ import { SmokeRunStatus } from './SmokeRunStatus';
4
+ import { SmokeTestResult } from './SmokeTestResult';
5
+
6
+ // One smoke run: POST /smoke/run creates it, GET /smoke/run/{runId} polls it.
7
+ // The shape is the part-2 contract; part 3 only grows what `tests` contains.
8
+ export type SmokeRun = {
9
+ runId: string;
10
+ status: SmokeRunStatus;
11
+ startedAt: string;
12
+ finishedAt: Nullable<string>;
13
+ tests: SmokeTestResult[];
14
+ };
@@ -0,0 +1,5 @@
1
+ export enum SmokeRunStatus {
2
+ running = 'running',
3
+ passed = 'passed',
4
+ failed = 'failed',
5
+ }
@@ -0,0 +1,8 @@
1
+ // Counts derived from a run's test entries at read time, never stored, so they
2
+ // cannot drift from the entries themselves.
3
+ export type SmokeRunSummary = {
4
+ total: number;
5
+ completed: number;
6
+ passed: number;
7
+ failed: number;
8
+ };
@@ -0,0 +1,7 @@
1
+ import { SmokeRun } from './SmokeRun';
2
+ import { SmokeRunSummary } from './SmokeRunSummary';
3
+
4
+ // What GET /smoke/run/{runId} returns: the stored run plus derived counts.
5
+ export type SmokeRunWithSummary = SmokeRun & {
6
+ summary: SmokeRunSummary;
7
+ };
@@ -0,0 +1,15 @@
1
+ import { Nullable } from 'quidproquo';
2
+
3
+ import { SmokeTestStatus } from './SmokeTestStatus';
4
+
5
+ // One registered test's entry in a run. `name` is the stable key; `id` is the
6
+ // test's 1-based position in the registry, for humans, and shifts if the
7
+ // registry is reordered, so nothing should key on it.
8
+ export type SmokeTestResult = {
9
+ id: number;
10
+ name: string;
11
+ status: SmokeTestStatus;
12
+ message: string;
13
+ startedAt: Nullable<string>;
14
+ finishedAt: Nullable<string>;
15
+ };
@@ -0,0 +1,6 @@
1
+ export enum SmokeTestStatus {
2
+ pending = 'pending',
3
+ running = 'running',
4
+ passed = 'passed',
5
+ failed = 'failed',
6
+ }
@@ -0,0 +1,7 @@
1
+ export * from './SmokeProbeRecord';
2
+ export * from './SmokeRun';
3
+ export * from './SmokeRunStatus';
4
+ export * from './SmokeRunSummary';
5
+ export * from './SmokeRunWithSummary';
6
+ export * from './SmokeTestResult';
7
+ export * from './SmokeTestStatus';
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "../../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "noImplicitOverride": true,
8
+ "noImplicitReturns": true,
9
+ "noFallthroughCasesInSwitch": true
10
+ },
11
+ "files": [],
12
+ "include": [],
13
+ "references": [
14
+ {
15
+ "path": "./tsconfig.lib.json"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "declaration": true,
6
+ "types": [
7
+ "node"
8
+ ],
9
+ "rootDir": ".",
10
+ "composite": true
11
+ },
12
+ "include": [
13
+ "src/**/*.ts"
14
+ ],
15
+ "exclude": [
16
+ "jest.config.ts",
17
+ "src/**/*.spec.ts"
18
+ ]
19
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@qpqjs/test-service",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "commonjs",
6
+ "scripts": {
7
+ "validate-ts": "tsc -p tsconfig.app.json --noEmit"
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ import { defineDevServerOptions } from 'quidproquo-dev-server/config';
2
+
3
+ import { QpqjsServiceEnum } from '@qpqjs/constants';
4
+ import { defineQpqjsService } from '@qpqjs/service-utils';
5
+
6
+ import { defineSmoke } from './smoke/config/defineSmoke';
7
+
8
+ export default [
9
+ defineDevServerOptions({ port: 3083 }),
10
+
11
+ // never change the app name, it will result in a new stack!
12
+ defineQpqjsService(
13
+ QpqjsServiceEnum.Test,
14
+ __dirname,
15
+ '../../../../../../dist/apps/qpqjs/services/test/service'
16
+ ),
17
+
18
+ defineSmoke(),
19
+ ];
@@ -0,0 +1,102 @@
1
+ import {
2
+ defineEventBus,
3
+ defineKeyValueStore,
4
+ defineParameter,
5
+ defineQueue,
6
+ defineRoute,
7
+ defineSecret,
8
+ defineStorageDrive,
9
+ QPQConfig,
10
+ QpqFunctionRuntime,
11
+ } from 'quidproquo';
12
+
13
+ import { SMOKE_PROBE_DRIVE, SMOKE_PROBE_STORE } from '@qpqjs/constants';
14
+ import { SmokeProbeRecord } from '@qpqjs/test-models';
15
+
16
+ import { SMOKE_RUNS_STORE } from '../constants/SMOKE_RUNS_STORE';
17
+ import {
18
+ SMOKE_PROBE_EVENT_BUS,
19
+ SMOKE_PROBE_EVENT_QUEUE,
20
+ SMOKE_PROBE_EVENT_TYPE,
21
+ SMOKE_PROBE_PARAMETER,
22
+ SMOKE_PROBE_PARAMETER_VALUE,
23
+ SMOKE_PROBE_SECRET,
24
+ } from '../constants/smokeProbe';
25
+ import {
26
+ SMOKE_RUN_QUEUE,
27
+ SMOKE_RUN_REQUESTED_MESSAGE_TYPE,
28
+ } from '../constants/smokeRunQueue';
29
+
30
+ // Everything the smoke feature needs: the run store, the queue runs execute
31
+ // on, and the two routes. Runtimes are located relative to this file, so the
32
+ // module can move as a unit.
33
+ //
34
+ // The routes look public (no user directory, no api keys) but carry a
35
+ // per-runtime action processor override that swaps the route auth decode for
36
+ // the GitHub OIDC validator - so ONLY a GitHub Actions run of our repo,
37
+ // holding an OIDC token with the qpq-smoke audience and matching pinned
38
+ // claims, gets past the preamble. Everything else 401s, tokenless included.
39
+ export const defineSmoke = (): QPQConfig => {
40
+ const githubOidcAuth: QpqFunctionRuntime[] = [
41
+ {
42
+ basePath: __dirname,
43
+ relativePath: '../processors/github/getGithubOidcAuthProcessors',
44
+ functionName: 'getGithubOidcAuthProcessors',
45
+ },
46
+ ];
47
+
48
+ return [
49
+ // One record per run, keyed by runId; the queue entry updates it as tests
50
+ // complete and the GET route polls it.
51
+ defineKeyValueStore(SMOKE_RUNS_STORE, 'runId'),
52
+
53
+ defineQueue(SMOKE_RUN_QUEUE, {
54
+ [SMOKE_RUN_REQUESTED_MESSAGE_TYPE]: {
55
+ basePath: __dirname,
56
+ relativePath: '../queue/onSmokeRunRequested',
57
+ functionName: 'onSmokeRunRequested',
58
+ },
59
+ }),
60
+
61
+ // Throwaway probe resources, one per kind of owned resource the tag-based
62
+ // IAM grants cover. The store's `category` index is what the KVS test
63
+ // queries through, proving the `table/*/index/*` half of the grant.
64
+ defineKeyValueStore<SmokeProbeRecord>(SMOKE_PROBE_STORE, 'probeId', [], {
65
+ indexes: ['category'],
66
+ }),
67
+ defineParameter(SMOKE_PROBE_PARAMETER, {
68
+ value: SMOKE_PROBE_PARAMETER_VALUE,
69
+ }),
70
+ defineSecret(SMOKE_PROBE_SECRET),
71
+ defineStorageDrive(SMOKE_PROBE_DRIVE),
72
+
73
+ // Event bus test path: publish to the bus, the subscribed queue's entry
74
+ // writes a marker into the probe store, the test polls for it.
75
+ defineEventBus(SMOKE_PROBE_EVENT_BUS),
76
+ defineQueue(
77
+ SMOKE_PROBE_EVENT_QUEUE,
78
+ {
79
+ [SMOKE_PROBE_EVENT_TYPE]: {
80
+ basePath: __dirname,
81
+ relativePath: '../queue/onSmokeProbeEvent',
82
+ functionName: 'onSmokeProbeEvent',
83
+ },
84
+ },
85
+ { eventBusSubscriptions: [SMOKE_PROBE_EVENT_BUS] }
86
+ ),
87
+
88
+ defineRoute('POST', '/smoke/run', {
89
+ basePath: __dirname,
90
+ relativePath: '../controller/askRunSmokeTests',
91
+ functionName: 'askRunSmokeTests',
92
+ actionProcessors: githubOidcAuth,
93
+ }),
94
+
95
+ defineRoute('GET', '/smoke/run/{runId}', {
96
+ basePath: __dirname,
97
+ relativePath: '../controller/askGetSmokeRun',
98
+ functionName: 'askGetSmokeRun',
99
+ actionProcessors: githubOidcAuth,
100
+ }),
101
+ ];
102
+ };
@@ -0,0 +1 @@
1
+ export * from './defineSmoke';
@@ -0,0 +1,2 @@
1
+ // Key value store holding one record per smoke run, keyed by runId.
2
+ export const SMOKE_RUNS_STORE = 'smokeRuns';
@@ -0,0 +1,19 @@
1
+ // The pinned claims for GitHub Actions OIDC tokens accepted by the smoke
2
+ // endpoint. All public, none secret.
3
+
4
+ // The only issuer GitHub Actions OIDC tokens can come from.
5
+ export const GITHUB_OIDC_ISSUER = 'https://token.actions.githubusercontent.com';
6
+
7
+ // Where GitHub publishes the signing keys for its Actions OIDC tokens.
8
+ export const GITHUB_OIDC_JWKS_URL =
9
+ 'https://token.actions.githubusercontent.com/.well-known/jwks';
10
+
11
+ // Dedicated audience the deployed-smoke workflow job requests its token with.
12
+ // Tokens minted for any other purpose (e.g. the AWS deploy role) carry a
13
+ // different audience and are rejected.
14
+ export const GITHUB_OIDC_AUDIENCE = 'qpq-smoke';
15
+
16
+ // The immutable GitHub id of qpqjs/quidproquo, fetched once with
17
+ // `gh api repos/qpqjs/quidproquo --jq .id`. Pinned instead of the repo NAME
18
+ // because names can be reassigned; ids cannot.
19
+ export const GITHUB_REPOSITORY_ID = '571382961';
@@ -0,0 +1,4 @@
1
+ export * from './githubOidc';
2
+ export * from './SMOKE_RUNS_STORE';
3
+ export * from './smokeProbe';
4
+ export * from './smokeRunQueue';
@@ -0,0 +1,14 @@
1
+ // Throwaway resources the smoke tests exercise, one per kind of owned
2
+ // resource the service role is granted by tag / name convention (see the
3
+ // tag-based IAM grants in quidproquo-deploy-awscdk). Nothing else uses them.
4
+ // The store and drive names live in @qpqjs/constants because testa reaches
5
+ // them cross-service.
6
+ export const SMOKE_PROBE_PARAMETER = 'smokeProbe';
7
+ export const SMOKE_PROBE_PARAMETER_VALUE = 'smoke-probe-parameter';
8
+ export const SMOKE_PROBE_SECRET = 'smokeProbe';
9
+ export const SMOKE_PROBE_EVENT_BUS = 'smokeProbe';
10
+
11
+ // The queue subscribed to the probe event bus, and the message type that
12
+ // flows bus -> queue -> store marker for the event bus test.
13
+ export const SMOKE_PROBE_EVENT_QUEUE = 'smokeProbeEvents';
14
+ export const SMOKE_PROBE_EVENT_TYPE = 'smokeProbeEvent';
@@ -0,0 +1,6 @@
1
+ // The queue a smoke run is executed from, and the one message type on it.
2
+ // POST /smoke/run creates the run record and sends this message; the queue
3
+ // entry picks it up and runs the registered tests, so the request returns at
4
+ // once and polling shows real progress.
5
+ export const SMOKE_RUN_QUEUE = 'smokeRuns';
6
+ export const SMOKE_RUN_REQUESTED_MESSAGE_TYPE = 'smokeRunRequested';
@@ -0,0 +1,27 @@
1
+ import {
2
+ AskResponse,
3
+ HTTPEvent,
4
+ HTTPEventResponse,
5
+ qpqWebServerUtils,
6
+ } from 'quidproquo';
7
+
8
+ import { askFindSmokeRun } from '../logic/smokeRun/askFindSmokeRun';
9
+ import { summarizeSmokeRun } from '../logic/smokeRun/summarizeSmokeRun';
10
+
11
+ // GET /smoke/run/{runId}. The deployed-smoke script polls this until the run
12
+ // leaves 'running' or its deadline passes.
13
+ export function* askGetSmokeRun(
14
+ event: HTTPEvent,
15
+ params: { runId: string }
16
+ ): AskResponse<HTTPEventResponse> {
17
+ const smokeRun = yield* askFindSmokeRun(params.runId);
18
+
19
+ if (!smokeRun) {
20
+ return qpqWebServerUtils.toJsonEventResponse(
21
+ { message: `no smoke run [${params.runId}]` },
22
+ 404
23
+ );
24
+ }
25
+
26
+ return qpqWebServerUtils.toJsonEventResponse(summarizeSmokeRun(smokeRun));
27
+ }
@@ -0,0 +1,19 @@
1
+ import {
2
+ AskResponse,
3
+ HTTPEvent,
4
+ HTTPEventResponse,
5
+ qpqWebServerUtils,
6
+ } from 'quidproquo';
7
+
8
+ import { askStartSmokeRun } from '../logic/smokeRun/askStartSmokeRun';
9
+
10
+ // POST /smoke/run. Auth happened in the route preamble via the GitHub OIDC
11
+ // decode override attached to this route's runtime. Starts the run on the
12
+ // queue and hands back the runId; status is polled separately.
13
+ export function* askRunSmokeTests(
14
+ event: HTTPEvent
15
+ ): AskResponse<HTTPEventResponse> {
16
+ const smokeRun = yield* askStartSmokeRun();
17
+
18
+ return qpqWebServerUtils.toJsonEventResponse({ runId: smokeRun.runId });
19
+ }
@@ -0,0 +1,2 @@
1
+ export * from './askGetSmokeRun';
2
+ export * from './askRunSmokeTests';
@@ -0,0 +1,16 @@
1
+ import { askKeyValueStoreGet, AskResponse, Nullable } from 'quidproquo';
2
+
3
+ import { SmokeRun } from '@qpqjs/test-models';
4
+
5
+ import { SMOKE_RUNS_STORE } from '../constants/SMOKE_RUNS_STORE';
6
+
7
+ export function* askGetSmokeRunById(
8
+ runId: string
9
+ ): AskResponse<Nullable<SmokeRun>> {
10
+ const smokeRun = yield* askKeyValueStoreGet<SmokeRun>(
11
+ SMOKE_RUNS_STORE,
12
+ runId
13
+ );
14
+
15
+ return smokeRun || null;
16
+ }
@@ -0,0 +1,9 @@
1
+ import { askKeyValueStoreUpsert, AskResponse } from 'quidproquo';
2
+
3
+ import { SmokeRun } from '@qpqjs/test-models';
4
+
5
+ import { SMOKE_RUNS_STORE } from '../constants/SMOKE_RUNS_STORE';
6
+
7
+ export function* askSaveSmokeRun(smokeRun: SmokeRun): AskResponse<void> {
8
+ yield* askKeyValueStoreUpsert<SmokeRun>(SMOKE_RUNS_STORE, smokeRun);
9
+ }
@@ -0,0 +1,2 @@
1
+ export * from './askGetSmokeRunById';
2
+ export * from './askSaveSmokeRun';
@@ -0,0 +1,9 @@
1
+ export * from './config';
2
+ export * from './constants';
3
+ export * from './controller';
4
+ export * from './data';
5
+ export * from './logic';
6
+ export * from './models';
7
+ export * from './processors';
8
+ export * from './queue';
9
+ export * from './tests';
@@ -0,0 +1 @@
1
+ export * from './verifyGithubOidcToken';