@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.
- package/README.md +28 -1
- package/dist/{chunk-Z7TXSZR4.js → chunk-OYFQKSJN.js} +9 -1
- package/dist/i18n.js +1 -1
- package/dist/index.cjs +305 -14
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +304 -15
- package/dist/prisma.js +3 -3
- package/dist/session.cjs +297 -0
- package/dist/session.d.cts +226 -0
- package/dist/session.d.ts +226 -0
- package/dist/session.js +244 -0
- package/dist/trpc.cjs +122 -0
- package/dist/trpc.d.cts +59 -0
- package/dist/trpc.d.ts +59 -0
- package/dist/trpc.js +73 -0
- package/docs/rules/github-actions-least-privilege-permissions.md +71 -0
- package/docs/rules/github-actions-no-template-injection.md +93 -0
- package/docs/rules/idempotency-key-parity.md +83 -0
- package/docs/rules/session-epoch-captured.md +83 -0
- package/docs/rules/session-kind-stamped.md +81 -0
- package/docs/rules/session-landing-declared.md +87 -0
- package/docs/rules/session-mint-callers.md +77 -0
- package/package.json +17 -7
|
@@ -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.
|
|
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.
|
|
65
|
-
"@noctcore/eslint-plugin-prisma": "^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.
|
|
83
|
-
"@typescript-eslint/parser": "^8.
|
|
84
|
-
"eslint": "^10.
|
|
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
|
}
|