@o3co/create-auth-provider 0.16.0 → 0.17.0-rc.2
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/README.ja.md +66 -21
- package/README.md +76 -31
- package/dist/index.d.mts +33 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +118 -59
- package/dist/internal/template-filter.d.mts +7 -10
- package/dist/internal/template-filter.d.mts.map +1 -1
- package/dist/internal/template-filter.mjs +7 -10
- package/package.json +6 -4
- package/templates/standalone/.dockerignore +15 -2
- package/templates/standalone/.env.example +59 -29
- package/templates/standalone/Dockerfile +6 -2
- package/templates/standalone/README.ja.md +324 -169
- package/templates/standalone/README.md +618 -208
- package/templates/standalone/config/application.conf +211 -352
- package/templates/standalone/config/clients.yaml +2 -0
- package/templates/standalone/config/clients.yaml.example +4 -0
- package/templates/standalone/config/development.conf +13 -4
- package/templates/standalone/config/mailpit.conf +8 -0
- package/templates/standalone/config/production.conf +5 -6
- package/templates/standalone/config/reference.conf +418 -0
- package/templates/standalone/docker-compose.mailpit.yml +36 -0
- package/templates/standalone/docker-compose.production.yml +63 -32
- package/templates/standalone/docker-compose.yml +13 -3
- package/templates/standalone/gitignore +1 -0
- package/templates/standalone/package.json +9 -6
- package/templates/standalone/src/__tests__/adapters.test.mts +419 -0
- package/templates/standalone/src/__tests__/admission-lifecycle.test.mts +87 -0
- package/templates/standalone/src/__tests__/all-modules-composition.fixture.mts +287 -198
- package/templates/standalone/src/__tests__/all-modules-composition.multi.test.mts +71 -35
- package/templates/standalone/src/__tests__/all-modules-composition.test.mts +148 -94
- package/templates/standalone/src/__tests__/audit-sink.test.mts +84 -81
- package/templates/standalone/src/__tests__/config-notices.test.mts +154 -0
- package/templates/standalone/src/__tests__/configPath.test.mts +13 -11
- package/templates/standalone/src/__tests__/core-federations.test.mts +249 -0
- package/templates/standalone/src/__tests__/core-sections.test.mts +190 -0
- package/templates/standalone/src/__tests__/device-code-store-client-module.test.mts +10 -15
- package/templates/standalone/src/__tests__/documented-env-overrides.test.mts +970 -288
- package/templates/standalone/src/__tests__/federation-grants-composition.test.mts +421 -86
- package/templates/standalone/src/__tests__/federation-grants-survive-logout.test.mts +87 -72
- package/templates/standalone/src/__tests__/federation-token-refresh-outage.test.mts +16 -8
- package/templates/standalone/src/__tests__/federation-types.test.mts +239 -0
- package/templates/standalone/src/__tests__/google-session.fixture.mts +97 -93
- package/templates/standalone/src/__tests__/host-routes.test.mts +4 -11
- package/templates/standalone/src/__tests__/library-reference-resolution.smoke.test.mts +1 -1
- package/templates/standalone/src/__tests__/library-references.fixture.mts +188 -0
- package/templates/standalone/src/__tests__/lifecycle-pending-close.test.mts +216 -0
- package/templates/standalone/src/__tests__/listen.test.mts +6 -13
- package/templates/standalone/src/__tests__/logger-projection.test.mts +1 -1
- package/templates/standalone/src/__tests__/mail-sender.test.mts +134 -0
- package/templates/standalone/src/__tests__/mailpit-compose.test.mts +326 -0
- package/templates/standalone/src/__tests__/metrics.test.mts +4 -9
- package/templates/standalone/src/__tests__/mfa-routes-budget.test.mts +122 -0
- package/templates/standalone/src/__tests__/mfa-switch.redis.test.mts +123 -0
- package/templates/standalone/src/__tests__/mfa-switch.test.mts +825 -0
- package/templates/standalone/src/__tests__/own-modules.test.mts +1486 -0
- package/templates/standalone/src/__tests__/post-logout-redirect.test.mts +10 -14
- package/templates/standalone/src/__tests__/redis-connection-error-log.test.mts +1 -5
- package/templates/standalone/src/__tests__/redis-rate-limiter-config-survives.test.mts +116 -81
- package/templates/standalone/src/__tests__/refresh-token-family-client-module.test.mts +25 -31
- package/templates/standalone/src/__tests__/replica-safety.test.mts +265 -146
- package/templates/standalone/src/__tests__/router-error-answers.test.mts +4 -7
- package/templates/standalone/src/__tests__/scaffold-assets.test.mts +278 -103
- package/templates/standalone/src/__tests__/sections.test.mts +480 -0
- package/templates/standalone/src/__tests__/session-lifecycle.test.mts +215 -0
- package/templates/standalone/src/__tests__/session-logout-invalidates-token.test.mts +69 -61
- package/templates/standalone/src/__tests__/session-logout-lifecycle.test.mts +130 -0
- package/templates/standalone/src/__tests__/session-requirements.test.mts +382 -0
- package/templates/standalone/src/__tests__/shipped-config-notices.test.mts +270 -0
- package/templates/standalone/src/__tests__/shutdown.test.mts +163 -96
- package/templates/standalone/src/__tests__/smoke.test.mts +176 -258
- package/templates/standalone/src/__tests__/store-credential.test.mts +88 -52
- package/templates/standalone/src/__tests__/supertest-loopback.test.mts +182 -11
- package/templates/standalone/src/__tests__/three-tier-resolution.test.mts +131 -102
- package/templates/standalone/src/__tests__/two-phase-config.test.mts +604 -0
- package/templates/standalone/src/__tests__/upstream-amr.acceptance.test.mts +382 -0
- package/templates/standalone/src/adapters.mts +162 -0
- package/templates/standalone/src/app.mts +65 -79
- package/templates/standalone/src/bootRefusal.mts +117 -0
- package/templates/standalone/src/buildModules.mts +220 -309
- package/templates/standalone/src/configPath.mts +449 -29
- package/templates/standalone/src/listen.mts +12 -18
- package/templates/standalone/src/logger.mts +31 -60
- package/templates/standalone/src/metrics.mts +24 -47
- package/templates/standalone/src/mfaSwitch.mts +285 -0
- package/templates/standalone/src/modules.mts +423 -629
- package/templates/standalone/src/rootRenames.mts +96 -0
- package/templates/standalone/src/routes.mts +8 -14
- package/templates/standalone/src/sections.mts +367 -0
- package/templates/standalone/src/shutdown.mts +45 -123
- package/templates/standalone/tests/index.test.js +6 -5
- package/templates/standalone/tests/package-lock.json +1615 -2223
- package/templates/standalone/tests/package.json +2 -2
- package/templates/standalone/tests/vitest.config.mjs +26 -0
- package/templates/standalone/vitest.config.mts +8 -7
- package/templates/standalone/vitest.supertest-loopback.mts +97 -69
- package/templates/versions.json +18 -15
- package/templates/standalone/src/__tests__/access-token-lifetime-alias.test.mts +0 -135
- package/templates/standalone/src/__tests__/google-federation-config-module.test.mts +0 -199
- package/templates/standalone/src/__tests__/oidc-federation-config-module.test.mts +0 -138
|
@@ -16,32 +16,31 @@
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* The all-modules composition of `all-modules-composition.test.mts` on more
|
|
19
|
-
* than one replica: every shared store on Redis, `deployment.mode = "multi"`,
|
|
19
|
+
* than one replica: every shared store on Redis, `core.deployment.mode = "multi"`,
|
|
20
20
|
* every module the template can turn on switched on together.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* routes, the same discovery document as on one replica.
|
|
22
|
+
* With every module on, the all-Redis composition boots with nothing declaring
|
|
23
|
+
* replica-unsafe state, and each store switched back to memory is refused at
|
|
24
|
+
* boot, naming the module. The Redis adapters change nothing a client can
|
|
25
|
+
* see: the same routes, the same discovery document as on one replica.
|
|
27
26
|
*
|
|
28
27
|
* ioredis, node-redis and connect-redis are stand-ins, as in
|
|
29
|
-
* `replica-safety.test.mts`:
|
|
30
|
-
*
|
|
31
|
-
* Redis server to run against — `packages/redis` runs its adapters against
|
|
32
|
-
* one.
|
|
28
|
+
* `replica-safety.test.mts`: nothing here issues a command. `packages/redis`
|
|
29
|
+
* runs its adapters against a real server.
|
|
33
30
|
*/
|
|
34
31
|
|
|
35
32
|
import { type Module, replicaUnsafeReason } from "@o3co/auth-provider-core";
|
|
36
33
|
import * as redisPackage from "@o3co/auth-provider-redis";
|
|
37
34
|
import request from "supertest";
|
|
38
35
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
36
|
+
import { readOwnLayers, resolveForBoot } from "#/configPath.mjs";
|
|
39
37
|
import { standaloneRedisClientsModule } from "#/modules.mjs";
|
|
40
38
|
import {
|
|
41
39
|
type Composition,
|
|
42
40
|
compose,
|
|
43
41
|
composedModules,
|
|
44
42
|
MULTI_ENV,
|
|
43
|
+
ownFiles,
|
|
45
44
|
resolveConfig,
|
|
46
45
|
} from "./all-modules-composition.fixture.mjs";
|
|
47
46
|
|
|
@@ -110,7 +109,7 @@ const MULTI = { env: MULTI_ENV, shippedRefreshTokenFamilyStore: true } as const;
|
|
|
110
109
|
|
|
111
110
|
/** What `buildModules` lists with every switch on and every shared store on Redis. */
|
|
112
111
|
const ALL_ON_REDIS_MODULES = [
|
|
113
|
-
"
|
|
112
|
+
"session-store",
|
|
114
113
|
"federation-grant-background",
|
|
115
114
|
"federation-grants",
|
|
116
115
|
"oauth",
|
|
@@ -118,19 +117,22 @@ const ALL_ON_REDIS_MODULES = [
|
|
|
118
117
|
"oauth-authorization",
|
|
119
118
|
"jwks",
|
|
120
119
|
"session",
|
|
121
|
-
"federation
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
"
|
|
120
|
+
"federation-google-type",
|
|
121
|
+
"federation-oidc",
|
|
122
|
+
"logging",
|
|
123
|
+
"http",
|
|
124
|
+
"key-store",
|
|
126
125
|
"test:repositories",
|
|
127
|
-
"
|
|
128
|
-
"
|
|
126
|
+
"audit-sink",
|
|
127
|
+
"standard-smtp-mail-sender",
|
|
128
|
+
"redis-clients",
|
|
129
129
|
"redis-federation-token-store",
|
|
130
130
|
"redis-federation-grant-store",
|
|
131
131
|
"redis-federation-grant-intent-store",
|
|
132
|
-
"
|
|
132
|
+
"redis-session-stores",
|
|
133
|
+
"core-session-lifecycle",
|
|
133
134
|
"redis-rate-limiter",
|
|
135
|
+
"redis-attempt-counter",
|
|
134
136
|
"redis-code-repository",
|
|
135
137
|
"redis-access-token-denylist",
|
|
136
138
|
"redis-replay-seen-set",
|
|
@@ -141,11 +143,18 @@ const ALL_ON_REDIS_MODULES = [
|
|
|
141
143
|
"subject-revocation-service",
|
|
142
144
|
];
|
|
143
145
|
|
|
144
|
-
describe('every module on, every shared store on Redis, deployment.mode = "multi"', () => {
|
|
146
|
+
describe('every module on, every shared store on Redis, core.deployment.mode = "multi"', () => {
|
|
145
147
|
it("lists every module, none declaring replica-unsafe state, and boots", async () => {
|
|
146
|
-
const
|
|
148
|
+
const own = readOwnLayers(ownFiles(MULTI_ENV), { env: MULTI_ENV });
|
|
149
|
+
const config = resolveConfig(MULTI_ENV, own);
|
|
150
|
+
const modules = composedModules(config, MULTI);
|
|
147
151
|
expect(modules.map((m) => m.name)).toEqual(ALL_ON_REDIS_MODULES);
|
|
148
|
-
|
|
152
|
+
// Each module's section at its name, as boot is handed it: a
|
|
153
|
+
// declaration made from the section is answered for it.
|
|
154
|
+
const sections = resolveForBoot(own, modules, config) as unknown as Record<string, unknown>;
|
|
155
|
+
for (const module of modules) {
|
|
156
|
+
expect(replicaUnsafeReason(module, sections[module.name]), module.name).toBeUndefined();
|
|
157
|
+
}
|
|
149
158
|
current = await compose(MULTI);
|
|
150
159
|
expect(current.handle.readinessProbes.map((p) => p.name)).toContain("redis");
|
|
151
160
|
});
|
|
@@ -166,21 +175,36 @@ describe('every module on, every shared store on Redis, deployment.mode = "multi
|
|
|
166
175
|
expect(discovery.body).toEqual(single.discovery);
|
|
167
176
|
});
|
|
168
177
|
|
|
178
|
+
it("boots as multi on CORE_DEPLOYMENT_MODE=multi alone", async () => {
|
|
179
|
+
expect(MULTI_ENV).toMatchObject({ CORE_DEPLOYMENT_MODE: "multi" });
|
|
180
|
+
expect(MULTI_ENV).not.toHaveProperty("DEPLOYMENT_MODE");
|
|
181
|
+
current = await compose(MULTI);
|
|
182
|
+
expect(current.handle.components.deploymentMode).toBe("multi");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("boots as multi on DEPLOYMENT_MODE=multi beside CORE_DEPLOYMENT_MODE=multi, as the umbrella sets them", async () => {
|
|
186
|
+
current = await compose({
|
|
187
|
+
...MULTI,
|
|
188
|
+
env: { ...MULTI_ENV, DEPLOYMENT_MODE: "multi", CORE_DEPLOYMENT_MODE: "multi" },
|
|
189
|
+
});
|
|
190
|
+
expect(current.handle.components.deploymentMode).toBe("multi");
|
|
191
|
+
});
|
|
192
|
+
|
|
169
193
|
/**
|
|
170
194
|
* Each store's switch back to memory, alone, with every module on. The
|
|
171
195
|
* boot names the module that declared the state it would fork.
|
|
172
196
|
*/
|
|
173
197
|
const MEMORY_SWITCHES: ReadonlyArray<readonly [variable: string, module: string]> = [
|
|
174
|
-
["
|
|
175
|
-
["
|
|
176
|
-
["
|
|
177
|
-
["
|
|
178
|
-
["
|
|
179
|
-
["
|
|
180
|
-
["
|
|
181
|
-
["
|
|
182
|
-
["
|
|
183
|
-
["
|
|
198
|
+
["SESSION_STORE_STORAGE_TYPE", "session-store"],
|
|
199
|
+
["ADAPTERS_USER_SESSION_STORES", "standalone-in-memory-session-stores"],
|
|
200
|
+
["ADAPTERS_CODE_REPOSITORY", "standalone-in-memory-code-repository"],
|
|
201
|
+
["ADAPTERS_FEDERATION_TOKEN_STORE", "standalone-in-memory-federation-token-store"],
|
|
202
|
+
["ADAPTERS_RATE_LIMITER", "core-rate-limiter-memory"],
|
|
203
|
+
["ADAPTERS_ACCESS_TOKEN_DENYLIST", "core-access-token-denylist-memory"],
|
|
204
|
+
["ADAPTERS_REPLAY_SEEN_SET", "core-replay-seen-set-memory"],
|
|
205
|
+
["ADAPTERS_CONSENT_STORE", "core-consent-store-memory"],
|
|
206
|
+
["ADAPTERS_FEDERATION_GRANT_STORE", "core-federation-grant-store-memory"],
|
|
207
|
+
["ADAPTERS_FEDERATION_GRANT_INTENT_STORE", "core-federation-grant-intent-store-memory"],
|
|
184
208
|
];
|
|
185
209
|
|
|
186
210
|
it.each(MEMORY_SWITCHES)("%s=memory is refused at boot, naming %s", async (variable, module) => {
|
|
@@ -193,6 +217,18 @@ describe('every module on, every shared store on Redis, deployment.mode = "multi
|
|
|
193
217
|
});
|
|
194
218
|
});
|
|
195
219
|
|
|
220
|
+
it("ADAPTERS_ATTEMPT_COUNTER=memory is refused at boot: the login would count its attempts per replica", async () => {
|
|
221
|
+
await expect(
|
|
222
|
+
compose({ ...MULTI, env: { ...MULTI_ENV, ADAPTERS_ATTEMPT_COUNTER: "memory" } }),
|
|
223
|
+
).rejects.toMatchObject({
|
|
224
|
+
name: "BootError",
|
|
225
|
+
reason: "contribute-factory-failed",
|
|
226
|
+
cause: {
|
|
227
|
+
message: expect.stringContaining('no shared attemptCounter is wired for "login"'),
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
196
232
|
it("names every memory store together when every switch is memory", async () => {
|
|
197
233
|
const env = { ...MULTI_ENV };
|
|
198
234
|
for (const [variable] of MEMORY_SWITCHES) env[variable] = "memory";
|
|
@@ -212,8 +248,8 @@ describe("the shared Redis socket can back every store the Redis package ships",
|
|
|
212
248
|
* the others to the manifest with the modules that read them (the device
|
|
213
249
|
* grant's code store, WebAuthn's challenge store), and each requires its
|
|
214
250
|
* client from this module. One it does not provide is a boot refused with
|
|
215
|
-
* `missing-required-component
|
|
216
|
-
*
|
|
251
|
+
* `missing-required-component`, which `modules.mts` guards against for
|
|
252
|
+
* the device-code store by name.
|
|
217
253
|
*/
|
|
218
254
|
const storeModules: Module[] = Object.entries(redisPackage).flatMap(([name, value]) => {
|
|
219
255
|
if (name.endsWith("ModuleFor") && typeof value === "function") {
|
|
@@ -226,7 +262,7 @@ describe("the shared Redis socket can back every store the Redis package ships",
|
|
|
226
262
|
});
|
|
227
263
|
|
|
228
264
|
it.each(storeModules.map((m) => [m.name, m] as const))(
|
|
229
|
-
"%s: its client slot is provided by
|
|
265
|
+
"%s: its client slot is provided by redis-clients",
|
|
230
266
|
(_name, module) => {
|
|
231
267
|
const provided = Object.keys(standaloneRedisClientsModule.provides ?? {});
|
|
232
268
|
const clients = (module.requires ?? []).filter((slot) => String(slot).endsWith("Client"));
|