@noctcore/lint-meta-rules 0.4.2 → 0.6.0

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,77 @@
1
+ # `session-mint-callers`
2
+
3
+ > The method that mints a session is callable only from an allowlist of files, so a new sign-in
4
+ > entry point cannot skip the gate in front of it.
5
+
6
+ Import it from the `session` entry point:
7
+
8
+ ```ts
9
+ import { createSessionMintCallersRule } from '@noctcore/lint-meta-rules/session';
10
+ ```
11
+
12
+ ## Why
13
+
14
+ Most auth stacks have one method that turns an authenticated principal into a session: it writes the
15
+ session store, sets the cookie, rotates CSRF. In front of it sits a gate (a second-factor challenge, an
16
+ epoch capture) that every sign-in is meant to pass through. A new entry point, typically an OAuth
17
+ callback added months later, that calls the mint directly signs the user in with the gate skipped, and
18
+ nothing fails: the flow works, its tests pass, the gate's tests pass. The mint is the one door into a
19
+ session, so this rule fences the door by caller.
20
+
21
+ ## What it flags
22
+
23
+ A file matched by `sourceGlobs` that calls `.<mintCall>(` (whitespace before the paren allowed) and is
24
+ not in `allowedCallers`.
25
+
26
+ ## What it leaves alone
27
+
28
+ - The method's definition (`async establishSession(`): the leading dot is required.
29
+ - `.<mintCall>Something(`: only whitespace may sit between the name and the paren.
30
+ - Files ending in an `excludeSuffixes` entry (tests drive the mint directly), and paths with a
31
+ `skipDirs` segment.
32
+ - Everything outside `sourceGlobs`, including a lint-meta rule module that quotes the call.
33
+
34
+ With no `mintCall` the rule is inert.
35
+
36
+ ## Factory
37
+
38
+ ```ts
39
+ createSessionMintCallersRule(options?: SessionMintCallersOptions): IMetaRule
40
+ ```
41
+
42
+ | Option | Type | Default | Meaning |
43
+ | --- | --- | --- | --- |
44
+ | `id` | `string` | `'session-mint-callers'` | Rule id. |
45
+ | `mintCall` | `string` | none (inert) | The method whose call mints a session, matched as `.<mintCall>(`. |
46
+ | `allowedCallers` | `string[]` | `[]` | Repo-relative files that may call it, matched exactly: the method's home, the gate, and flows with no gate to pass (signup, a re-issue to a caller who already holds a session). |
47
+ | `gateCall` | `string` | none | The method a sign-in entry point must call instead, named in the message. |
48
+ | `sourceGlobs` | `string[]` | `[]` (inert) | Application source to read. |
49
+ | `skipDirs` | `string[]` | `node_modules`, `.git`, `dist`, `.turbo`, `coverage` | Path segments skipped. |
50
+ | `excludeSuffixes` | `string[]` | `.spec.ts`, `.spec.tsx`, `.test.ts`, `.test.tsx` | File endings skipped. |
51
+ | `hint` | `string` | none | Appended to every message, e.g. a pointer to your auth docs. |
52
+ | `ciCritical` | `boolean` | `true` | Whether a violation fails CI. |
53
+
54
+ ## Worked example: Settly
55
+
56
+ ```ts
57
+ const AUTH = 'apps/api/src/modules/auth/services';
58
+
59
+ createSessionMintCallersRule({
60
+ id: 'establish-session-callers',
61
+ mintCall: 'establishSession',
62
+ gateCall: 'beginOrEstablish',
63
+ allowedCallers: [
64
+ `${AUTH}/auth-shared.service.ts`,
65
+ `${AUTH}/two-factor-challenge.service.ts`,
66
+ `${AUTH}/register.service.ts`,
67
+ `${AUTH}/password-change.service.ts`,
68
+ `${AUTH}/session-management.service.ts`,
69
+ ],
70
+ sourceGlobs: ['apps/*/{src,test,tests,security-spec}/**/*.{ts,tsx}'],
71
+ });
72
+ ```
73
+
74
+ ## When not to use it
75
+
76
+ If sessions are minted by a framework you do not call (a hosted auth provider's middleware), there is no
77
+ method to fence.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noctcore/lint-meta-rules",
3
- "version": "0.4.2",
3
+ "version": "0.6.0",
4
4
  "description": "Portable, parameterized lint-meta rules — whole-repo / cross-file invariants ESLint cannot reach — for the @noctcore/harness lint-meta runner.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,6 +28,16 @@
28
28
  "import": "./dist/resolved-config.js",
29
29
  "require": "./dist/resolved-config.cjs"
30
30
  },
31
+ "./session": {
32
+ "types": "./dist/session.d.ts",
33
+ "import": "./dist/session.js",
34
+ "require": "./dist/session.cjs"
35
+ },
36
+ "./trpc": {
37
+ "types": "./dist/trpc.d.ts",
38
+ "import": "./dist/trpc.js",
39
+ "require": "./dist/trpc.cjs"
40
+ },
31
41
  "./package.json": "./package.json"
32
42
  },
33
43
  "files": [
@@ -56,13 +66,13 @@
56
66
  "homepage": "https://github.com/noctcore/eslint-plugins/tree/main/packages/lint-meta-rules",
57
67
  "bugs": "https://github.com/noctcore/eslint-plugins/issues",
58
68
  "scripts": {
59
- "build": "tsup src/index.ts src/i18n.ts src/prisma.ts src/resolved-config.ts --format esm,cjs --dts --clean",
69
+ "build": "tsup src/index.ts src/i18n.ts src/prisma.ts src/resolved-config.ts src/session.ts src/trpc.ts --format esm,cjs --dts --clean",
60
70
  "typecheck": "tsc --noEmit",
61
71
  "test": "bun test"
62
72
  },
63
73
  "dependencies": {
64
- "@noctcore/eslint-plugin-contracts": "^0.6.0",
65
- "@noctcore/eslint-plugin-prisma": "^0.4.0",
74
+ "@noctcore/eslint-plugin-contracts": "^0.7.0",
75
+ "@noctcore/eslint-plugin-prisma": "^0.5.0",
66
76
  "@noctcore/harness": "^0.3.0",
67
77
  "@typescript-eslint/utils": "^8.61.1"
68
78
  },
@@ -79,9 +89,9 @@
79
89
  }
80
90
  },
81
91
  "devDependencies": {
82
- "@types/node": "^22.0.0",
83
- "@typescript-eslint/parser": "^8.61.1",
84
- "eslint": "^10.7.0",
92
+ "@types/node": "^22.20.3",
93
+ "@typescript-eslint/parser": "^8.70.0",
94
+ "eslint": "^10.10.0",
85
95
  "tsup": "^8.5.1",
86
96
  "typescript": "^5.6.0"
87
97
  }