@xemahq/xema-npm-auth-plugin 0.1.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.
@@ -0,0 +1,26 @@
1
+ import { JwtVerifier } from './jwks';
2
+ import { type PluginLogger } from './logger';
3
+ import { type PackageAccessContext, type RemoteUser, type VerdaccioCallback, type XemaAuthPluginConfig } from './types';
4
+ interface VerdaccioStuff {
5
+ logger?: unknown;
6
+ config?: unknown;
7
+ }
8
+ export interface XemaNpmAuthPlugin {
9
+ authenticate(user: string, password: string, cb: VerdaccioCallback): void;
10
+ allow_access(user: RemoteUser, pkg: PackageAccessContext, cb: VerdaccioCallback): void;
11
+ allow_publish(user: RemoteUser, pkg: PackageAccessContext, cb: VerdaccioCallback): void;
12
+ }
13
+ export interface BuildPluginDeps {
14
+ env?: NodeJS.ProcessEnv;
15
+ verifier?: JwtVerifier;
16
+ logger?: PluginLogger;
17
+ }
18
+ export declare function buildPlugin(config: XemaAuthPluginConfig, deps?: BuildPluginDeps): XemaNpmAuthPlugin;
19
+ declare function pluginFactory(config: XemaAuthPluginConfig, stuff?: VerdaccioStuff): XemaNpmAuthPlugin;
20
+ export default pluginFactory;
21
+ export { pluginFactory };
22
+ export { buildPlugin as __buildBiomeForTests };
23
+ export { JwtVerifier } from './jwks';
24
+ export * from './types';
25
+ export { classifyPackage, evaluateAcl, packageTierToVisibility } from './acl';
26
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAGL,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAE1B,MAAM,SAAS,CAAC;AAKjB,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,iBAAiB,GACpB,IAAI,CAAC;IACR,YAAY,CACV,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,oBAAoB,EACzB,EAAE,EAAE,iBAAiB,GACpB,IAAI,CAAC;IACR,aAAa,CACX,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,oBAAoB,EACzB,EAAE,EAAE,iBAAiB,GACpB,IAAI,CAAC;CACT;AAED,MAAM,WAAW,eAAe;IAE9B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAExB,QAAQ,CAAC,EAAE,WAAW,CAAC;IAEvB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAMD,wBAAgB,WAAW,CACzB,MAAM,EAAE,oBAAoB,EAC5B,IAAI,GAAE,eAAoB,GACzB,iBAAiB,CAgInB;AA2ED,iBAAS,aAAa,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,GAAE,cAAmB,GAAG,iBAAiB,CAGlG;AAID,eAAe,aAAa,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,OAAO,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.packageTierToVisibility = exports.evaluateAcl = exports.classifyPackage = exports.JwtVerifier = void 0;
18
+ exports.buildPlugin = buildPlugin;
19
+ exports.__buildBiomeForTests = buildPlugin;
20
+ exports.pluginFactory = pluginFactory;
21
+ const acl_1 = require("./acl");
22
+ const jwks_1 = require("./jwks");
23
+ const logger_1 = require("./logger");
24
+ const types_1 = require("./types");
25
+ const ANONYMOUS_USERNAME = '$anonymous';
26
+ const AUTHENTICATED_GROUP = '$authenticated';
27
+ function buildPlugin(config, deps = {}) {
28
+ const env = deps.env ?? process.env;
29
+ const logger = deps.logger ?? (0, logger_1.adaptVerdaccioLogger)(undefined);
30
+ const verifier = deps.verifier ??
31
+ new jwks_1.JwtVerifier({
32
+ jwksUrl: requireEnv(config.keycloakRealmUrl ?? env.KEYCLOAK_REALM_URL, 'KEYCLOAK_REALM_URL'),
33
+ ...(config.expectedIssuer !== undefined
34
+ ? { expectedIssuer: config.expectedIssuer }
35
+ : env.KEYCLOAK_EXPECTED_ISSUER !== undefined
36
+ ? { expectedIssuer: env.KEYCLOAK_EXPECTED_ISSUER }
37
+ : {}),
38
+ ...(config.jwksRefreshMs !== undefined
39
+ ? { refreshMs: config.jwksRefreshMs }
40
+ : {}),
41
+ logger,
42
+ });
43
+ return {
44
+ authenticate(user, password, cb) {
45
+ const cid = (0, logger_1.newCorrelationId)();
46
+ if (!password) {
47
+ logger.debug('authenticate skipped (empty password = anonymous read)', {
48
+ cid,
49
+ user,
50
+ });
51
+ cb(null, false);
52
+ return;
53
+ }
54
+ void verifier
55
+ .verify(password)
56
+ .then((claims) => {
57
+ logger.info('authenticate ok', {
58
+ cid,
59
+ sub: claims.sub,
60
+ orgId: claims.x_org_id,
61
+ role: claims.x_role,
62
+ });
63
+ cb(null, [
64
+ AUTHENTICATED_GROUP,
65
+ `xema:role:${claims.x_role}`,
66
+ `xema:org:${claims.x_org_id}`,
67
+ `xema:sub:${claims.sub}`,
68
+ ]);
69
+ })
70
+ .catch((err) => {
71
+ logger.warn('authenticate denied', {
72
+ cid,
73
+ user,
74
+ error: err.message,
75
+ });
76
+ cb(null, false);
77
+ });
78
+ },
79
+ allow_access(remoteUser, pkg, cb) {
80
+ const cid = (0, logger_1.newCorrelationId)();
81
+ const claims = claimsFromRemoteUser(remoteUser);
82
+ const decision = (0, acl_1.evaluateAcl)({
83
+ packageName: pkg.name,
84
+ action: 'access',
85
+ claims,
86
+ });
87
+ if (decision.allow) {
88
+ logger.debug('allow_access ok', {
89
+ cid,
90
+ pkg: pkg.name,
91
+ orgId: claims?.x_org_id,
92
+ role: claims?.x_role,
93
+ });
94
+ cb(null, true);
95
+ return;
96
+ }
97
+ logger.warn('allow_access denied', {
98
+ cid,
99
+ pkg: pkg.name,
100
+ reason: decision.reason,
101
+ message: decision.message,
102
+ orgId: claims?.x_org_id,
103
+ role: claims?.x_role,
104
+ });
105
+ cb(buildDenyError(decision.reason, decision.message), false);
106
+ },
107
+ allow_publish(remoteUser, pkg, cb) {
108
+ const cid = (0, logger_1.newCorrelationId)();
109
+ const claims = claimsFromRemoteUser(remoteUser);
110
+ const decision = (0, acl_1.evaluateAcl)({
111
+ packageName: pkg.name,
112
+ action: 'publish',
113
+ claims,
114
+ });
115
+ if (decision.allow) {
116
+ logger.info('allow_publish ok', {
117
+ cid,
118
+ pkg: pkg.name,
119
+ orgId: claims?.x_org_id,
120
+ role: claims?.x_role,
121
+ sub: claims?.sub,
122
+ });
123
+ cb(null, true);
124
+ return;
125
+ }
126
+ logger.warn('allow_publish denied', {
127
+ cid,
128
+ pkg: pkg.name,
129
+ reason: decision.reason,
130
+ message: decision.message,
131
+ orgId: claims?.x_org_id,
132
+ role: claims?.x_role,
133
+ });
134
+ cb(buildDenyError(decision.reason, decision.message), false);
135
+ },
136
+ };
137
+ }
138
+ function requireEnv(value, name) {
139
+ if (!value) {
140
+ throw new Error(`[xema-jwt] required env "${name}" is missing — plugin refuses to start (constitutional rule: no silent fallback to "auth disabled")`);
141
+ }
142
+ return value;
143
+ }
144
+ function claimsFromRemoteUser(remoteUser) {
145
+ const groups = remoteUser.real_groups ?? remoteUser.groups ?? [];
146
+ if (!groups.includes(AUTHENTICATED_GROUP)) {
147
+ return undefined;
148
+ }
149
+ let role;
150
+ let orgId;
151
+ let sub;
152
+ for (const g of groups) {
153
+ if (g.startsWith('xema:role:')) {
154
+ const candidate = g.slice('xema:role:'.length);
155
+ if (candidate === types_1.XemaRegistryRole.Platform ||
156
+ candidate === types_1.XemaRegistryRole.OrgAdmin ||
157
+ candidate === types_1.XemaRegistryRole.OrgMember ||
158
+ candidate === types_1.XemaRegistryRole.Anonymous) {
159
+ role = candidate;
160
+ }
161
+ }
162
+ else if (g.startsWith('xema:org:')) {
163
+ orgId = g.slice('xema:org:'.length);
164
+ }
165
+ else if (g.startsWith('xema:sub:')) {
166
+ sub = g.slice('xema:sub:'.length);
167
+ }
168
+ }
169
+ if (!role || !orgId || !sub) {
170
+ return undefined;
171
+ }
172
+ return {
173
+ sub,
174
+ exp: Number.MAX_SAFE_INTEGER,
175
+ x_org_id: orgId,
176
+ x_role: role,
177
+ };
178
+ }
179
+ function buildDenyError(reason, message) {
180
+ const err = new Error(message);
181
+ err.code = 'XEMA_ACL_DENIED';
182
+ err.reason = reason;
183
+ return err;
184
+ }
185
+ function pluginFactory(config, stuff = {}) {
186
+ const logger = (0, logger_1.adaptVerdaccioLogger)(stuff.logger);
187
+ return buildPlugin(config, { logger });
188
+ }
189
+ exports.default = pluginFactory;
190
+ var jwks_2 = require("./jwks");
191
+ Object.defineProperty(exports, "JwtVerifier", { enumerable: true, get: function () { return jwks_2.JwtVerifier; } });
192
+ __exportStar(require("./types"), exports);
193
+ var acl_2 = require("./acl");
194
+ Object.defineProperty(exports, "classifyPackage", { enumerable: true, get: function () { return acl_2.classifyPackage; } });
195
+ Object.defineProperty(exports, "evaluateAcl", { enumerable: true, get: function () { return acl_2.evaluateAcl; } });
196
+ Object.defineProperty(exports, "packageTierToVisibility", { enumerable: true, get: function () { return acl_2.packageTierToVisibility; } });
197
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ export declare enum XemaRegistryRole {
2
+ Platform = "platform",
3
+ OrgAdmin = "org_admin",
4
+ OrgMember = "org_member",
5
+ Anonymous = "anonymous"
6
+ }
7
+ export interface XemaJwtClaims {
8
+ sub: string;
9
+ exp: number;
10
+ iat?: number;
11
+ x_org_id: string;
12
+ x_role: XemaRegistryRole;
13
+ }
14
+ export type AclDecision = {
15
+ allow: true;
16
+ } | {
17
+ allow: false;
18
+ reason: AclDenyReason;
19
+ message: string;
20
+ };
21
+ export declare enum AclDenyReason {
22
+ MissingJwt = "missing_jwt",
23
+ InvalidJwt = "invalid_jwt",
24
+ ExpiredJwt = "expired_jwt",
25
+ WrongRoleForSystem = "wrong_role_for_system",
26
+ WrongRoleForSystemShareablePublish = "wrong_role_for_system_shareable_publish",
27
+ AnonymousOrgRead = "anonymous_org_read",
28
+ CrossOrgAccess = "cross_org_access",
29
+ UnknownPackagePattern = "unknown_package_pattern"
30
+ }
31
+ export declare enum PackageTier {
32
+ System = "system",
33
+ SystemShareable = "system_shareable",
34
+ Org = "org",
35
+ Uplink = "uplink"
36
+ }
37
+ export interface ClassifiedPackage {
38
+ tier: PackageTier;
39
+ orgScope: string | null;
40
+ raw: string;
41
+ }
42
+ export interface PackageAccessContext {
43
+ name: string;
44
+ }
45
+ export interface RemoteUser {
46
+ name?: string | null;
47
+ groups?: string[];
48
+ real_groups?: string[];
49
+ error?: string;
50
+ }
51
+ export interface XemaAuthPluginConfig {
52
+ keycloakRealmUrl?: string;
53
+ expectedIssuer?: string;
54
+ jwksRefreshMs?: number;
55
+ }
56
+ export type VerdaccioCallback = (err: Error | null, result?: string[] | boolean) => void;
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAqBA,oBAAY,gBAAgB;IAC1B,QAAQ,aAAa;IACrB,QAAQ,cAAc;IACtB,SAAS,eAAe;IACxB,SAAS,cAAc;CACxB;AAGD,MAAM,WAAW,aAAa;IAE5B,GAAG,EAAE,MAAM,CAAC;IAEZ,GAAG,EAAE,MAAM,CAAC;IAEZ,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;IAEjB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAOD,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,oBAAY,aAAa;IACvB,UAAU,gBAAgB;IAC1B,UAAU,gBAAgB;IAC1B,UAAU,gBAAgB;IAC1B,kBAAkB,0BAA0B;IAC5C,kCAAkC,4CAA4C;IAC9E,gBAAgB,uBAAuB;IACvC,cAAc,qBAAqB;IACnC,qBAAqB,4BAA4B;CAClD;AAGD,oBAAY,WAAW;IACrB,MAAM,WAAW;IACjB,eAAe,qBAAqB;IACpC,GAAG,QAAQ;IAEX,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,WAAW,CAAC;IAElB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,GAAG,EAAE,MAAM,CAAC;CACb;AAGD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAOD,MAAM,WAAW,oBAAoB;IAKnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAGD,MAAM,MAAM,iBAAiB,GAAG,CAC9B,GAAG,EAAE,KAAK,GAAG,IAAI,EACjB,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,KACxB,IAAI,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PackageTier = exports.AclDenyReason = exports.XemaRegistryRole = void 0;
4
+ var XemaRegistryRole;
5
+ (function (XemaRegistryRole) {
6
+ XemaRegistryRole["Platform"] = "platform";
7
+ XemaRegistryRole["OrgAdmin"] = "org_admin";
8
+ XemaRegistryRole["OrgMember"] = "org_member";
9
+ XemaRegistryRole["Anonymous"] = "anonymous";
10
+ })(XemaRegistryRole || (exports.XemaRegistryRole = XemaRegistryRole = {}));
11
+ var AclDenyReason;
12
+ (function (AclDenyReason) {
13
+ AclDenyReason["MissingJwt"] = "missing_jwt";
14
+ AclDenyReason["InvalidJwt"] = "invalid_jwt";
15
+ AclDenyReason["ExpiredJwt"] = "expired_jwt";
16
+ AclDenyReason["WrongRoleForSystem"] = "wrong_role_for_system";
17
+ AclDenyReason["WrongRoleForSystemShareablePublish"] = "wrong_role_for_system_shareable_publish";
18
+ AclDenyReason["AnonymousOrgRead"] = "anonymous_org_read";
19
+ AclDenyReason["CrossOrgAccess"] = "cross_org_access";
20
+ AclDenyReason["UnknownPackagePattern"] = "unknown_package_pattern";
21
+ })(AclDenyReason || (exports.AclDenyReason = AclDenyReason = {}));
22
+ var PackageTier;
23
+ (function (PackageTier) {
24
+ PackageTier["System"] = "system";
25
+ PackageTier["SystemShareable"] = "system_shareable";
26
+ PackageTier["Org"] = "org";
27
+ PackageTier["Uplink"] = "uplink";
28
+ })(PackageTier || (exports.PackageTier = PackageTier = {}));
29
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAqBA,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,yCAAqB,CAAA;IACrB,0CAAsB,CAAA;IACtB,4CAAwB,CAAA;IACxB,2CAAuB,CAAA;AACzB,CAAC,EALW,gBAAgB,gCAAhB,gBAAgB,QAK3B;AAyBD,IAAY,aASX;AATD,WAAY,aAAa;IACvB,2CAA0B,CAAA;IAC1B,2CAA0B,CAAA;IAC1B,2CAA0B,CAAA;IAC1B,6DAA4C,CAAA;IAC5C,+FAA8E,CAAA;IAC9E,wDAAuC,CAAA;IACvC,oDAAmC,CAAA;IACnC,kEAAiD,CAAA;AACnD,CAAC,EATW,aAAa,6BAAb,aAAa,QASxB;AAGD,IAAY,WAMX;AAND,WAAY,WAAW;IACrB,gCAAiB,CAAA;IACjB,mDAAoC,CAAA;IACpC,0BAAW,CAAA;IAEX,gCAAiB,CAAA;AACnB,CAAC,EANW,WAAW,2BAAX,WAAW,QAMtB"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@xemahq/xema-npm-auth-plugin",
3
+ "version": "0.1.2",
4
+ "description": "Verdaccio auth plugin: validates Keycloak JWTs and enforces Xema's four-tier RegistryVisibilityTier ACL (System / SystemShareable / Org / External) on every authenticate/allow_access/allow_publish call.",
5
+ "main": "dist/plugin.cjs",
6
+ "types": "dist/plugin.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "publishConfig": {
12
+ "registry": "https://npm.pkg.github.com",
13
+ "access": "restricted"
14
+ },
15
+ "dependencies": {
16
+ "@xemahq/kernel-contracts": "^0.2.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/jest": "^30.0.0",
20
+ "@types/node": "25.2.3",
21
+ "esbuild": "^0.25.4",
22
+ "jest": "^30.3.0",
23
+ "ts-jest": "^29.4.9",
24
+ "typescript": "5.9.3"
25
+ },
26
+ "scripts": {
27
+ "clean": "rm -rf dist",
28
+ "typecheck": "tsc -p tsconfig.json --noEmit",
29
+ "build": "tsc -p tsconfig.json && node ./scripts/bundle.mjs",
30
+ "bundle": "node ./scripts/bundle.mjs",
31
+ "test": "jest --config jest.config.ts"
32
+ }
33
+ }