@jskit-ai/auth-core 0.1.50 → 0.1.52
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/package.descriptor.mjs +2 -2
- package/package.json +4 -2
- package/src/server/authPolicyContextResolverRegistry.js +125 -0
- package/src/server/authServiceDecoratorRegistry.js +56 -0
- package/src/server/providers/FastifyAuthPolicyServiceProvider.js +19 -2
- package/src/shared/commands/authCommandValidators.js +2 -0
- package/test/authApi.test.js +5 -1
- package/test/authPolicyContextResolverRegistry.test.js +56 -0
- package/test/authServiceDecoratorRegistry.test.js +51 -0
- package/test/providerRuntime.test.js +13 -1
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
"packageVersion": 1,
|
|
3
3
|
"packageId": "@jskit-ai/auth-core",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.52",
|
|
5
5
|
"kind": "runtime",
|
|
6
6
|
"dependsOn": [
|
|
7
7
|
"@jskit-ai/value-app-config-shared"
|
|
@@ -69,7 +69,7 @@ export default Object.freeze({
|
|
|
69
69
|
"mutations": {
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"runtime": {
|
|
72
|
-
"@jskit-ai/kernel": "0.1.
|
|
72
|
+
"@jskit-ai/kernel": "0.1.53",
|
|
73
73
|
"@fastify/cookie": "^11.0.2",
|
|
74
74
|
"@fastify/csrf-protection": "^7.1.0",
|
|
75
75
|
"@fastify/rate-limit": "^10.3.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/auth-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.52",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
"./server/providers/AccessCoreServiceProvider": "./src/server/providers/AccessCoreServiceProvider.js",
|
|
10
10
|
"./server/providers/FastifyAuthPolicyServiceProvider": "./src/server/providers/FastifyAuthPolicyServiceProvider.js",
|
|
11
|
+
"./server/authPolicyContextResolverRegistry": "./src/server/authPolicyContextResolverRegistry.js",
|
|
12
|
+
"./server/authServiceDecoratorRegistry": "./src/server/authServiceDecoratorRegistry.js",
|
|
11
13
|
"./server/utils": "./src/server/utils.js",
|
|
12
14
|
"./server/validators": "./src/server/validators.js",
|
|
13
15
|
"./server/inviteTokens": "./src/server/inviteTokens.js",
|
|
@@ -44,7 +46,7 @@
|
|
|
44
46
|
"./shared/commands/authSessionReadCommand": "./src/shared/commands/authSessionReadCommand.js"
|
|
45
47
|
},
|
|
46
48
|
"dependencies": {
|
|
47
|
-
"@jskit-ai/kernel": "0.1.
|
|
49
|
+
"@jskit-ai/kernel": "0.1.53",
|
|
48
50
|
"@fastify/cookie": "^11.0.2",
|
|
49
51
|
"@fastify/csrf-protection": "^7.1.0",
|
|
50
52
|
"@fastify/rate-limit": "^10.3.0",
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { normalizePermissionList } from "@jskit-ai/kernel/shared/support/permissions";
|
|
2
|
+
import { registerTaggedSingleton, resolveTaggedEntries } from "@jskit-ai/kernel/server/registries";
|
|
3
|
+
|
|
4
|
+
const AUTH_POLICY_CONTEXT_RESOLVER_TAG = "jskit.auth.policy.context.resolvers";
|
|
5
|
+
|
|
6
|
+
function normalizeAuthPolicyContextResolver(entry) {
|
|
7
|
+
if (typeof entry === "function") {
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
resolverId: String(entry.name || "anonymous"),
|
|
10
|
+
order: 0,
|
|
11
|
+
resolveAuthPolicyContext: entry
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!entry || typeof entry !== "object" || typeof entry.resolveAuthPolicyContext !== "function") {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const resolverId = String(entry.resolverId || "anonymous");
|
|
20
|
+
const order = Number.isFinite(entry.order) ? Number(entry.order) : 0;
|
|
21
|
+
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
...entry,
|
|
24
|
+
resolverId,
|
|
25
|
+
order,
|
|
26
|
+
resolveAuthPolicyContext: entry.resolveAuthPolicyContext
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function registerAuthPolicyContextResolver(app, token, factory) {
|
|
31
|
+
registerTaggedSingleton(app, token, factory, AUTH_POLICY_CONTEXT_RESOLVER_TAG, {
|
|
32
|
+
context: "registerAuthPolicyContextResolver"
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveAuthPolicyContextResolvers(scope) {
|
|
37
|
+
return resolveTaggedEntries(scope, AUTH_POLICY_CONTEXT_RESOLVER_TAG)
|
|
38
|
+
.map((entry, index) => ({
|
|
39
|
+
resolver: normalizeAuthPolicyContextResolver(entry),
|
|
40
|
+
index
|
|
41
|
+
}))
|
|
42
|
+
.filter((entry) => Boolean(entry.resolver))
|
|
43
|
+
.sort((left, right) => {
|
|
44
|
+
if (left.resolver.order !== right.resolver.order) {
|
|
45
|
+
return left.resolver.order - right.resolver.order;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return left.index - right.index;
|
|
49
|
+
})
|
|
50
|
+
.map((entry) => entry.resolver);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function mergeAuthPolicyContexts(contexts = []) {
|
|
54
|
+
const merged = {};
|
|
55
|
+
let hasValues = false;
|
|
56
|
+
const permissions = new Set();
|
|
57
|
+
|
|
58
|
+
for (const context of Array.isArray(contexts) ? contexts : [contexts]) {
|
|
59
|
+
if (!context || typeof context !== "object") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const [key, value] of Object.entries(context)) {
|
|
64
|
+
if (key === "permissions") {
|
|
65
|
+
for (const permission of normalizePermissionList(value)) {
|
|
66
|
+
permissions.add(permission);
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (value === undefined) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
merged[key] = value;
|
|
76
|
+
hasValues = true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (permissions.size > 0) {
|
|
81
|
+
merged.permissions = Object.freeze([...permissions]);
|
|
82
|
+
hasValues = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return hasValues ? Object.freeze(merged) : null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function composeAuthPolicyContextResolvers(resolvers = []) {
|
|
89
|
+
const normalizedResolvers = (Array.isArray(resolvers) ? resolvers : [resolvers])
|
|
90
|
+
.map((entry, index) => ({
|
|
91
|
+
resolver: normalizeAuthPolicyContextResolver(entry),
|
|
92
|
+
index
|
|
93
|
+
}))
|
|
94
|
+
.filter((entry) => Boolean(entry.resolver))
|
|
95
|
+
.sort((left, right) => {
|
|
96
|
+
if (left.resolver.order !== right.resolver.order) {
|
|
97
|
+
return left.resolver.order - right.resolver.order;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return left.index - right.index;
|
|
101
|
+
})
|
|
102
|
+
.map((entry) => entry.resolver);
|
|
103
|
+
|
|
104
|
+
if (normalizedResolvers.length < 1) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return async function resolveComposedAuthPolicyContext(input = {}) {
|
|
109
|
+
const contexts = [];
|
|
110
|
+
|
|
111
|
+
for (const resolver of normalizedResolvers) {
|
|
112
|
+
contexts.push(await resolver.resolveAuthPolicyContext(input));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return mergeAuthPolicyContexts(contexts);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
AUTH_POLICY_CONTEXT_RESOLVER_TAG,
|
|
121
|
+
registerAuthPolicyContextResolver,
|
|
122
|
+
resolveAuthPolicyContextResolvers,
|
|
123
|
+
mergeAuthPolicyContexts,
|
|
124
|
+
composeAuthPolicyContextResolvers
|
|
125
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { registerTaggedSingleton, resolveTaggedEntries } from "@jskit-ai/kernel/server/registries";
|
|
2
|
+
|
|
3
|
+
const AUTH_SERVICE_DECORATOR_TAG = "jskit.auth.service.decorators";
|
|
4
|
+
|
|
5
|
+
function normalizeAuthServiceDecorator(entry) {
|
|
6
|
+
if (typeof entry === "function") {
|
|
7
|
+
return Object.freeze({
|
|
8
|
+
decoratorId: String(entry.name || "anonymous"),
|
|
9
|
+
order: 0,
|
|
10
|
+
decorateAuthService: entry
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!entry || typeof entry !== "object" || typeof entry.decorateAuthService !== "function") {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const decoratorId = String(entry.decoratorId || "anonymous");
|
|
19
|
+
const order = Number.isFinite(entry.order) ? Number(entry.order) : 0;
|
|
20
|
+
|
|
21
|
+
return Object.freeze({
|
|
22
|
+
...entry,
|
|
23
|
+
decoratorId,
|
|
24
|
+
order,
|
|
25
|
+
decorateAuthService: entry.decorateAuthService
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function registerAuthServiceDecorator(app, token, factory) {
|
|
30
|
+
registerTaggedSingleton(app, token, factory, AUTH_SERVICE_DECORATOR_TAG, {
|
|
31
|
+
context: "registerAuthServiceDecorator"
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveAuthServiceDecorators(scope) {
|
|
36
|
+
return resolveTaggedEntries(scope, AUTH_SERVICE_DECORATOR_TAG)
|
|
37
|
+
.map((entry, index) => ({
|
|
38
|
+
decorator: normalizeAuthServiceDecorator(entry),
|
|
39
|
+
index
|
|
40
|
+
}))
|
|
41
|
+
.filter((entry) => Boolean(entry.decorator))
|
|
42
|
+
.sort((left, right) => {
|
|
43
|
+
if (left.decorator.order !== right.decorator.order) {
|
|
44
|
+
return left.decorator.order - right.decorator.order;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return left.index - right.index;
|
|
48
|
+
})
|
|
49
|
+
.map((entry) => entry.decorator);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
AUTH_SERVICE_DECORATOR_TAG,
|
|
54
|
+
registerAuthServiceDecorator,
|
|
55
|
+
resolveAuthServiceDecorators
|
|
56
|
+
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { registerActionContextContributor } from "@jskit-ai/kernel/server/actions";
|
|
2
2
|
import { registerRouteVisibilityResolver } from "@jskit-ai/kernel/server/http";
|
|
3
|
+
import {
|
|
4
|
+
composeAuthPolicyContextResolvers,
|
|
5
|
+
resolveAuthPolicyContextResolvers
|
|
6
|
+
} from "../authPolicyContextResolverRegistry.js";
|
|
3
7
|
import { authPolicyPlugin } from "../lib/plugin.js";
|
|
4
8
|
import { createAuthActionContextContributor } from "../lib/actionContextContributor.js";
|
|
5
9
|
import { createAuthRouteVisibilityResolver } from "../lib/routeVisibilityResolver.js";
|
|
@@ -74,17 +78,30 @@ class FastifyAuthPolicyServiceProvider {
|
|
|
74
78
|
const env = app.has("jskit.env") ? app.make("jskit.env") : {};
|
|
75
79
|
const fastify = app.make("jskit.fastify");
|
|
76
80
|
const authService = app.make("authService");
|
|
77
|
-
const
|
|
81
|
+
const legacyResolveContext =
|
|
78
82
|
typeof app.has === "function" && app.has("auth.policy.contextResolver")
|
|
79
83
|
? app.make("auth.policy.contextResolver")
|
|
80
84
|
: null;
|
|
81
85
|
|
|
82
|
-
if (
|
|
86
|
+
if (legacyResolveContext != null && typeof legacyResolveContext !== "function") {
|
|
83
87
|
throw new Error(
|
|
84
88
|
"FastifyAuthPolicyServiceProvider requires auth.policy.contextResolver to be a function when provided."
|
|
85
89
|
);
|
|
86
90
|
}
|
|
87
91
|
|
|
92
|
+
const resolveContext = composeAuthPolicyContextResolvers([
|
|
93
|
+
...resolveAuthPolicyContextResolvers(app),
|
|
94
|
+
...(legacyResolveContext
|
|
95
|
+
? [
|
|
96
|
+
{
|
|
97
|
+
resolverId: "legacy.auth.policy.contextResolver",
|
|
98
|
+
order: 1000,
|
|
99
|
+
resolveAuthPolicyContext: legacyResolveContext
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
: [])
|
|
103
|
+
]);
|
|
104
|
+
|
|
88
105
|
const pluginDeps = {
|
|
89
106
|
resolveActor: async (request) => {
|
|
90
107
|
if (authService && typeof authService.authenticateRequest === "function") {
|
|
@@ -204,6 +204,8 @@ const sessionResponseValidator = Object.freeze({
|
|
|
204
204
|
{
|
|
205
205
|
authenticated: Type.Boolean(),
|
|
206
206
|
username: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
|
|
207
|
+
email: Type.Optional(authEmailValidator.schema),
|
|
208
|
+
permissions: Type.Optional(Type.Array(Type.String({ minLength: 1, maxLength: 200 }))),
|
|
207
209
|
csrfToken: Type.String({ minLength: 1 }),
|
|
208
210
|
oauthProviders: Type.Array(oauthProviderCatalogEntryValidator.schema),
|
|
209
211
|
oauthDefaultProvider: Type.Union([oauthProviderValidator.schema, Type.Null()])
|
package/test/authApi.test.js
CHANGED
|
@@ -21,6 +21,7 @@ test("authApi exposes the expected methods and request routes", async () => {
|
|
|
21
21
|
"verifyOtp",
|
|
22
22
|
"oauthStartUrl",
|
|
23
23
|
"oauthComplete",
|
|
24
|
+
"devLoginAs",
|
|
24
25
|
"requestPasswordReset",
|
|
25
26
|
"completePasswordRecovery",
|
|
26
27
|
"resetPassword",
|
|
@@ -30,6 +31,7 @@ test("authApi exposes the expected methods and request routes", async () => {
|
|
|
30
31
|
await api.session();
|
|
31
32
|
await api.resendRegisterConfirmation({ email: "x@example.com" });
|
|
32
33
|
await api.login({ email: "x@example.com" });
|
|
34
|
+
await api.devLoginAs({ userId: "42" });
|
|
33
35
|
await api.logout();
|
|
34
36
|
|
|
35
37
|
assert.equal(calls[0].url, "/api/session");
|
|
@@ -37,8 +39,10 @@ test("authApi exposes the expected methods and request routes", async () => {
|
|
|
37
39
|
assert.equal(calls[1].options.method, "POST");
|
|
38
40
|
assert.equal(calls[2].url, "/api/login");
|
|
39
41
|
assert.equal(calls[2].options.method, "POST");
|
|
40
|
-
assert.equal(calls[3].url, "/api/
|
|
42
|
+
assert.equal(calls[3].url, "/api/dev-auth/login-as");
|
|
41
43
|
assert.equal(calls[3].options.method, "POST");
|
|
44
|
+
assert.equal(calls[4].url, "/api/logout");
|
|
45
|
+
assert.equal(calls[4].options.method, "POST");
|
|
42
46
|
});
|
|
43
47
|
|
|
44
48
|
test("authApi oauthStartUrl builds provider path with optional returnTo", () => {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createApplication } from "@jskit-ai/kernel/_testable";
|
|
4
|
+
import {
|
|
5
|
+
AUTH_POLICY_CONTEXT_RESOLVER_TAG,
|
|
6
|
+
composeAuthPolicyContextResolvers,
|
|
7
|
+
registerAuthPolicyContextResolver,
|
|
8
|
+
resolveAuthPolicyContextResolvers
|
|
9
|
+
} from "../src/server/authPolicyContextResolverRegistry.js";
|
|
10
|
+
|
|
11
|
+
test("auth policy context resolver registry resolves resolvers in order", async () => {
|
|
12
|
+
const app = createApplication();
|
|
13
|
+
|
|
14
|
+
registerAuthPolicyContextResolver(app, "test.auth.policy.context.permissions", () => ({
|
|
15
|
+
resolverId: "permissions",
|
|
16
|
+
order: 20,
|
|
17
|
+
async resolveAuthPolicyContext() {
|
|
18
|
+
return {
|
|
19
|
+
permissions: ["alpha.read"]
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
registerAuthPolicyContextResolver(app, "test.auth.policy.context.workspace", () => ({
|
|
25
|
+
resolverId: "workspace",
|
|
26
|
+
order: 10,
|
|
27
|
+
async resolveAuthPolicyContext() {
|
|
28
|
+
return {
|
|
29
|
+
workspace: { id: "11" },
|
|
30
|
+
membership: { roleSid: "member" },
|
|
31
|
+
permissions: ["workspace.read"]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const resolvers = resolveAuthPolicyContextResolvers(app);
|
|
37
|
+
assert.deepEqual(
|
|
38
|
+
resolvers.map((entry) => entry.resolverId),
|
|
39
|
+
["workspace", "permissions"]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const resolveContext = composeAuthPolicyContextResolvers(resolvers);
|
|
43
|
+
const context = await resolveContext({
|
|
44
|
+
actor: { id: "7" }
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
assert.deepEqual(context, {
|
|
48
|
+
workspace: { id: "11" },
|
|
49
|
+
membership: { roleSid: "member" },
|
|
50
|
+
permissions: ["workspace.read", "alpha.read"]
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("auth policy context resolver registry exports canonical tag", () => {
|
|
55
|
+
assert.equal(AUTH_POLICY_CONTEXT_RESOLVER_TAG, "jskit.auth.policy.context.resolvers");
|
|
56
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { createApplication } from "@jskit-ai/kernel/_testable";
|
|
4
|
+
import {
|
|
5
|
+
AUTH_SERVICE_DECORATOR_TAG,
|
|
6
|
+
registerAuthServiceDecorator,
|
|
7
|
+
resolveAuthServiceDecorators
|
|
8
|
+
} from "../src/server/authServiceDecoratorRegistry.js";
|
|
9
|
+
|
|
10
|
+
test("auth service decorator registry resolves decorators in order", () => {
|
|
11
|
+
const app = createApplication();
|
|
12
|
+
|
|
13
|
+
registerAuthServiceDecorator(app, "test.auth.decorator.zeta", () => ({
|
|
14
|
+
decoratorId: "zeta",
|
|
15
|
+
order: 50,
|
|
16
|
+
decorateAuthService(service) {
|
|
17
|
+
return {
|
|
18
|
+
...service,
|
|
19
|
+
trace: [...service.trace, "zeta"]
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
registerAuthServiceDecorator(app, "test.auth.decorator.alpha", () => ({
|
|
25
|
+
decoratorId: "alpha",
|
|
26
|
+
order: 10,
|
|
27
|
+
decorateAuthService(service) {
|
|
28
|
+
return {
|
|
29
|
+
...service,
|
|
30
|
+
trace: [...service.trace, "alpha"]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
const decorators = resolveAuthServiceDecorators(app);
|
|
36
|
+
assert.equal(decorators.length, 2);
|
|
37
|
+
assert.deepEqual(
|
|
38
|
+
decorators.map((entry) => entry.decoratorId),
|
|
39
|
+
["alpha", "zeta"]
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const decorated = decorators.reduce(
|
|
43
|
+
(service, decorator) => decorator.decorateAuthService(service),
|
|
44
|
+
{ trace: [] }
|
|
45
|
+
);
|
|
46
|
+
assert.deepEqual(decorated.trace, ["alpha", "zeta"]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("auth service decorator registry exports canonical tag", () => {
|
|
50
|
+
assert.equal(AUTH_SERVICE_DECORATOR_TAG, "jskit.auth.service.decorators");
|
|
51
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import { FastifyAuthPolicyServiceProvider } from "../src/server/providers/FastifyAuthPolicyServiceProvider.js";
|
|
4
|
+
import { AUTH_POLICY_CONTEXT_RESOLVER_TAG } from "../src/server/authPolicyContextResolverRegistry.js";
|
|
4
5
|
import { createFakeFastifyPolicyRuntime } from "../../../tooling/testUtils/fakeFastify.mjs";
|
|
5
6
|
|
|
6
7
|
test("FastifyAuthPolicyServiceProvider registers auth policy plugin through provider boot", async () => {
|
|
@@ -84,6 +85,17 @@ test("FastifyAuthPolicyServiceProvider wires optional auth policy context resolv
|
|
|
84
85
|
throw new Error(`Missing token ${String(token)}`);
|
|
85
86
|
}
|
|
86
87
|
return bag.get(token);
|
|
88
|
+
},
|
|
89
|
+
resolveTag(tag) {
|
|
90
|
+
if (tag !== AUTH_POLICY_CONTEXT_RESOLVER_TAG) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return [
|
|
95
|
+
async () => ({
|
|
96
|
+
permissions: ["settings.manage"]
|
|
97
|
+
})
|
|
98
|
+
];
|
|
87
99
|
}
|
|
88
100
|
};
|
|
89
101
|
|
|
@@ -108,5 +120,5 @@ test("FastifyAuthPolicyServiceProvider wires optional auth policy context resolv
|
|
|
108
120
|
assert.equal(request.workspace?.id, 11);
|
|
109
121
|
assert.equal(request.workspace?.slug, "acme");
|
|
110
122
|
assert.equal(request.membership?.roleSid, "member");
|
|
111
|
-
assert.deepEqual(request.permissions, ["projects.read"]);
|
|
123
|
+
assert.deepEqual(request.permissions, ["settings.manage", "projects.read"]);
|
|
112
124
|
});
|