permission-gap-detector 1.0.0 → 1.0.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/CHANGELOG.md +15 -2
- package/README.md +21 -37
- package/bin/cli.js +12 -6
- package/examples/clean-routes.json +17 -0
- package/package.json +2 -4
- package/src/checkPermissions.js +2 -2
- package/PROJECT_PROGRESS.md +0 -21
- package/VIVA_GUIDE.md +0 -52
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.0.
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
- Reject control characters in route paths before rendering reports.
|
|
6
|
+
- Accept UTF-8 BOM JSON files and literal filenames after `--`.
|
|
7
|
+
- Add command-specific help with documented exit codes.
|
|
8
|
+
- Expand regression coverage to 27 tests and include a clean route example.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 1.0.1
|
|
12
|
+
|
|
13
|
+
- Keep the distribution focused on source code, usage examples, and package documentation.
|
|
14
|
+
- Simplify the README and published file list.
|
|
15
|
+
|
|
16
|
+
## 1.0.0
|
|
4
17
|
|
|
5
18
|
- Add missing and invalid permission checks.
|
|
6
19
|
- Add duplicate and conflicting policy detection.
|
|
7
20
|
- Add summary counts and declaration coverage.
|
|
8
21
|
- Add CommonJS API and CLI with JSON output and exit codes.
|
|
9
|
-
- Add 20 tests
|
|
22
|
+
- Add 20 automated tests and usage examples.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Permission Gap Detector
|
|
2
2
|
|
|
3
|
-
A small, dependency-free CommonJS Node.js package that checks **declared API route permissions**.
|
|
3
|
+
A small, dependency-free CommonJS Node.js package that checks **declared API route permissions**.
|
|
4
4
|
|
|
5
5
|
## Problem statement
|
|
6
6
|
|
|
@@ -20,13 +20,13 @@ It does not inspect Express middleware or prove that an application is secure.
|
|
|
20
20
|
|
|
21
21
|
Requires Node.js 20 or newer and npm. No external dependencies.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Install from npm:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
npm install permission-gap-detector
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Alternatively, install directly from GitHub:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
npm install github:Aditya030207/npm-package-project
|
|
@@ -35,7 +35,7 @@ npm install github:Aditya030207/npm-package-project
|
|
|
35
35
|
Or run `npm pack` in this repository and install the resulting archive in another project:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
npm install /absolute/path/to/permission-gap-detector-1.0.
|
|
38
|
+
npm install /absolute/path/to/permission-gap-detector-1.0.2.tgz
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Basic usage
|
|
@@ -63,7 +63,7 @@ Input is an array of ordinary route objects. Each object needs:
|
|
|
63
63
|
| Field | Accepted values |
|
|
64
64
|
| --- | --- |
|
|
65
65
|
| `method` | GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, CONNECT, TRACE; case-insensitive |
|
|
66
|
-
| `path` | A string starting with `/`, without whitespace |
|
|
66
|
+
| `path` | A string starting with `/`, without whitespace or control characters |
|
|
67
67
|
| `access` | Exactly `public`, `authenticated`, or `admin` |
|
|
68
68
|
|
|
69
69
|
`public` allows anyone; `authenticated` requires a logged-in user; `admin` requires administrator access. These are declarations, not enforcement.
|
|
@@ -119,7 +119,7 @@ The three convenience functions return only their named findings. Use `auditRout
|
|
|
119
119
|
|
|
120
120
|
## CLI usage
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Run directly from npm:
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
125
|
npx permission-gap-detector check routes.json
|
|
@@ -132,18 +132,19 @@ npx --no-install permission-gap check routes.json
|
|
|
132
132
|
npx --no-install permission-gap check routes.json --json
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
For a direct shell command, globally install the package with `npm install -g permission-gap-detector`
|
|
135
|
+
For a direct shell command, globally install the package with `npm install -g permission-gap-detector` then run `permission-gap check routes.json`. Both binary names point to the same CLI.
|
|
136
136
|
|
|
137
|
-
From this repository
|
|
137
|
+
From this repository:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
140
|
node bin/cli.js check examples/routes.json
|
|
141
141
|
node bin/cli.js check examples/routes.json --json
|
|
142
142
|
node bin/cli.js --help
|
|
143
|
+
node bin/cli.js check --help
|
|
143
144
|
node bin/cli.js --version
|
|
144
145
|
```
|
|
145
146
|
|
|
146
|
-
Files must contain a JSON array, not an object wrapping the array. Paths are relative to the current working directory; quote paths containing spaces. Exit codes: **0** = no findings, **1** = audit findings, **2** = invalid command, unreadable file, malformed JSON, or non-array input. Human-readable failures go to stderr. With `--json`, failures are `{ "error": "message" }` on stdout.
|
|
147
|
+
UTF-8 files may begin with a byte order mark (BOM). Files must contain a JSON array, not an object wrapping the array. Paths are relative to the current working directory; quote paths containing spaces. Use `permission-gap check --json -- -routes.json` for a filename beginning with a dash; options must come before `--`. Exit codes: **0** = no findings, **1** = audit findings, **2** = invalid command, unreadable file, malformed JSON, or non-array input. Human-readable failures go to stderr. With `--json`, failures are `{ "error": "message" }` on stdout.
|
|
147
148
|
|
|
148
149
|
## Example output
|
|
149
150
|
|
|
@@ -177,6 +178,14 @@ Audit Complete
|
|
|
177
178
|
|
|
178
179
|
The example intentionally has issues and exits with code 1.
|
|
179
180
|
|
|
181
|
+
For a complete set of consistent declarations, run:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
node bin/cli.js check examples/clean-routes.json
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This example uses all three supported permissions, reports 100% declaration coverage with no findings, and exits with code 0. Compare it with `examples/routes.json` to see how missing and conflicting declarations change the result. Neither result verifies middleware enforcement.
|
|
188
|
+
|
|
180
189
|
## Development and testing
|
|
181
190
|
|
|
182
191
|
```bash
|
|
@@ -188,7 +197,7 @@ node examples/basic.js
|
|
|
188
197
|
npm pack --dry-run
|
|
189
198
|
```
|
|
190
199
|
|
|
191
|
-
The
|
|
200
|
+
The 27 automated tests use `node:test` and strict assertions. They cover valid policies, input validation, missing permissions, duplicates, conflicts, counting, immutability, reports, and CLI behavior with real temporary files and child processes.
|
|
192
201
|
|
|
193
202
|
## Source structure
|
|
194
203
|
|
|
@@ -204,41 +213,16 @@ npm-package-project/
|
|
|
204
213
|
├── tests/package.test.js # API and CLI tests
|
|
205
214
|
├── examples/
|
|
206
215
|
│ ├── basic.js
|
|
207
|
-
│
|
|
216
|
+
│ ├── routes.json
|
|
217
|
+
│ └── clean-routes.json
|
|
208
218
|
├── package.json
|
|
209
219
|
├── package-lock.json
|
|
210
220
|
├── README.md
|
|
211
221
|
├── CHANGELOG.md
|
|
212
|
-
├── PROJECT_PROGRESS.md
|
|
213
|
-
├── VIVA_GUIDE.md
|
|
214
222
|
├── LICENSE
|
|
215
223
|
└── .gitignore
|
|
216
224
|
```
|
|
217
225
|
|
|
218
|
-
## Publication
|
|
219
|
-
|
|
220
|
-
From the package directory, authenticate interactively and publish:
|
|
221
|
-
|
|
222
|
-
```bash
|
|
223
|
-
npm login
|
|
224
|
-
npm whoami
|
|
225
|
-
npm test
|
|
226
|
-
npm pack --dry-run
|
|
227
|
-
npm publish --access public
|
|
228
|
-
npm view permission-gap-detector@1.0.0 version
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
Complete any npm browser or two-factor authentication prompts. The name was absent from the npm registry on 19 October 2026; availability is not a reservation. If npm rejects the name, select an available name or your own npm scope and update the package metadata and usage instructions. After successful publication, update this README's pending status. Verify installation in a fresh directory with `npm install permission-gap-detector@1.0.0`, then run the basic usage example and CLI.
|
|
232
|
-
|
|
233
|
-
## College demonstration
|
|
234
|
-
|
|
235
|
-
1. Explain the missing-permission problem and the distinction between declarations and enforcement.
|
|
236
|
-
2. Run `npm test` to show the test results.
|
|
237
|
-
3. Run `node bin/cli.js check examples/routes.json` and explain the missing policy, two extra duplicates, one conflicting group, and 83.3% coverage.
|
|
238
|
-
4. In a copy of the JSON, assign `admin` to the DELETE route and remove the repeated GET definitions. Rerun to show no issues and 100% coverage.
|
|
239
|
-
5. Show the exported functions in `src/index.js` and the grouping loop in `src/checkDuplicates.js`.
|
|
240
|
-
6. Show the GitHub repository and install the packed archive into a separate project. Show the npm listing once publication is complete.
|
|
241
|
-
|
|
242
226
|
## Limitations
|
|
243
227
|
|
|
244
228
|
This audits only supplied route declarations. It does not scan source code, discover Express routes, execute middleware, validate tokens, enforce access rules, or assess application security. It does not infer route equivalence, inherited policies, Express mount paths, or wildcard matching. A public policy on a sensitive route is only detected as a conflict if another definition declares a different valid policy. Keep route declarations synchronized with the actual application.
|
package/bin/cli.js
CHANGED
|
@@ -4,24 +4,30 @@ const { auditRoutes } = require('../src');
|
|
|
4
4
|
const generateReport = require('../src/generateReport');
|
|
5
5
|
const { version } = require('../package.json');
|
|
6
6
|
const args = process.argv.slice(2);
|
|
7
|
-
|
|
8
|
-
const
|
|
7
|
+
// Arguments after -- are literal filenames, even when they begin with a dash.
|
|
8
|
+
const separator = args.indexOf('--');
|
|
9
|
+
const options = separator === -1 ? args : args.slice(0, separator);
|
|
10
|
+
const filenames = separator === -1 ? [] : args.slice(separator + 1);
|
|
11
|
+
const json = options.includes('--json');
|
|
12
|
+
const usage = 'Usage: permission-gap check <routes.json> [--json]\n permission-gap check [--json] -- <filename>\nOptions: --help, --version, --json\nExit codes: 0 = no findings, 1 = audit findings, 2 = input error';
|
|
9
13
|
|
|
10
14
|
try {
|
|
11
|
-
if (args.length === 1 && args[0] === '--help')
|
|
15
|
+
if ((args.length === 1 && args[0] === '--help') ||
|
|
16
|
+
(args.length === 2 && args[0] === 'check' && args[1] === '--help')) {
|
|
12
17
|
console.log(usage);
|
|
13
18
|
} else if (args.length === 1 && args[0] === '--version') {
|
|
14
19
|
console.log(version);
|
|
15
20
|
} else {
|
|
16
|
-
const positional =
|
|
17
|
-
|
|
21
|
+
const positional = [...options.filter(arg => arg !== '--json'), ...filenames];
|
|
22
|
+
const unknownOption = options.some(arg => arg.startsWith('-') && arg !== '--json');
|
|
23
|
+
if (positional.length !== 2 || positional[0] !== 'check' || unknownOption || options.filter(arg => arg === '--json').length > 1) {
|
|
18
24
|
throw new Error(usage);
|
|
19
25
|
}
|
|
20
26
|
let content;
|
|
21
27
|
try { content = fs.readFileSync(positional[1], 'utf8'); }
|
|
22
28
|
catch { throw new Error(`Cannot read file: ${positional[1]}`); }
|
|
23
29
|
let routes;
|
|
24
|
-
try { routes = JSON.parse(content); }
|
|
30
|
+
try { routes = JSON.parse(content.replace(/^\uFEFF/, '')); }
|
|
25
31
|
catch { throw new Error(`Invalid JSON in file: ${positional[1]}`); }
|
|
26
32
|
const result = auditRoutes(routes);
|
|
27
33
|
console.log(json ? JSON.stringify(result, null, 2) : generateReport(result));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "permission-gap-detector",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Check declared API route permissions for missing policies, duplicates, and conflicts.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -12,9 +12,7 @@
|
|
|
12
12
|
"src/",
|
|
13
13
|
"bin/",
|
|
14
14
|
"examples/",
|
|
15
|
-
"CHANGELOG.md"
|
|
16
|
-
"VIVA_GUIDE.md",
|
|
17
|
-
"PROJECT_PROGRESS.md"
|
|
15
|
+
"CHANGELOG.md"
|
|
18
16
|
],
|
|
19
17
|
"scripts": {
|
|
20
18
|
"test": "node --test",
|
package/src/checkPermissions.js
CHANGED
|
@@ -9,8 +9,8 @@ function validateRoutes(routes) {
|
|
|
9
9
|
const route = routes[index];
|
|
10
10
|
if (!route || typeof route !== 'object' || Array.isArray(route) ||
|
|
11
11
|
typeof route.method !== 'string' || !METHODS.includes(route.method.toUpperCase()) ||
|
|
12
|
-
typeof route.path !== 'string' || !route.path.startsWith('/') ||
|
|
13
|
-
invalidRoutes.push({ index, message: 'Expected an object with a supported HTTP method and a path starting with / without whitespace.' });
|
|
12
|
+
typeof route.path !== 'string' || !route.path.startsWith('/') || /[\s\x00-\x1f\x7f-\x9f]/.test(route.path)) {
|
|
13
|
+
invalidRoutes.push({ index, message: 'Expected an object with a supported HTTP method and a path starting with / without whitespace or control characters.' });
|
|
14
14
|
continue;
|
|
15
15
|
}
|
|
16
16
|
validRoutes.push({ index, method: route.method.toUpperCase(), path: route.path, access: route.access });
|
package/PROJECT_PROGRESS.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Project progress
|
|
2
|
-
|
|
3
|
-
## Intended schedule: 4–26 October 2026
|
|
4
|
-
|
|
5
|
-
These are planned milestones, not claims that work occurred on those dates.
|
|
6
|
-
|
|
7
|
-
| Planned dates | Milestones |
|
|
8
|
-
| --- | --- |
|
|
9
|
-
| October 4–6: Planning | Choose package idea; define problem statement; plan features. |
|
|
10
|
-
| October 7–10: Basic Setup | Initialize Node.js project; design route format; create package structure. |
|
|
11
|
-
| October 11–14: Core Development | Missing permission detection; permission validation; duplicate detection. |
|
|
12
|
-
| October 15–18: Remaining Features | Permission conflicts; coverage calculation; report output. |
|
|
13
|
-
| October 19–21: Testing | CLI; unit tests; input validation; bug fixes. |
|
|
14
|
-
| October 22–24: Documentation | README; usage examples; installation instructions; final testing. |
|
|
15
|
-
| October 25–26: Publication and Submission | NPM packaging; public GitHub repository; NPM publication; final demonstration. |
|
|
16
|
-
|
|
17
|
-
## Actual work
|
|
18
|
-
|
|
19
|
-
19 October 2026: Implemented the API and CLI, wrote and passed 20 automated tests, added examples, README, MIT license, changelog, and viva guide. Git commits use their real creation timestamps. Implementation was completed earlier than some planned milestones.
|
|
20
|
-
|
|
21
|
-
npm publication remains pending npm authentication. Publication and submission must not be presented as completed until separately verified.
|
package/VIVA_GUIDE.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Viva guide
|
|
2
|
-
|
|
3
|
-
**What problem does this package solve?**
|
|
4
|
-
It finds missing or inconsistent access declarations in a developer-maintained API route list.
|
|
5
|
-
|
|
6
|
-
**Why did we create it?**
|
|
7
|
-
It is easy to add an endpoint and forget to record who should access it. This reusable check makes omissions visible before review or release.
|
|
8
|
-
|
|
9
|
-
**How does auditRoutes() work?**
|
|
10
|
-
It checks that the input is an array, separates invalid route structures, checks access values, groups matching routes, and returns findings with counts and coverage. It does not change the input.
|
|
11
|
-
|
|
12
|
-
**How are duplicates detected?**
|
|
13
|
-
A Map groups definitions using the uppercase HTTP method plus the exact path. A group with more than one definition is duplicated. A group of three contributes two extra definitions to the duplicate count.
|
|
14
|
-
|
|
15
|
-
**How are permission conflicts detected?**
|
|
16
|
-
Within each duplicate group, a Set collects distinct supported permissions. More than one supported permission means a conflict. Invalid or missing values have separate findings.
|
|
17
|
-
|
|
18
|
-
**How is coverage calculated?**
|
|
19
|
-
Valid permission definitions / total submitted definitions × 100, rounded to one decimal. Empty input has 0%. Duplicate definitions stay in the denominator and may have valid policies. Coverage describes declaration completeness; even 100% can contain conflicts.
|
|
20
|
-
|
|
21
|
-
**Authentication versus authorization?**
|
|
22
|
-
Authentication checks who a person is, such as verifying their login. Authorization checks what that person may do, such as deleting a user. This package labels intended access but implements neither mechanism.
|
|
23
|
-
|
|
24
|
-
**What is package.json?**
|
|
25
|
-
It describes the npm package: name, version, main module, CLI commands, scripts, license, Node requirement, and repository. The files field controls which project files go into the published archive.
|
|
26
|
-
|
|
27
|
-
**What does module.exports do?**
|
|
28
|
-
It makes functions available to other files through CommonJS require(). Our entry point exports four named functions.
|
|
29
|
-
|
|
30
|
-
**How do automated tests work?**
|
|
31
|
-
Node's built-in runner executes test cases. Assertions compare actual behavior with expected results. CLI tests launch a real child process and use temporary files. npm test runs node --test. A failing assertion makes the test command fail.
|
|
32
|
-
|
|
33
|
-
**Why no dependencies?**
|
|
34
|
-
The checks need only loops, arrays, Map, and Set. Node already provides file reading, process arguments, and a test runner.
|
|
35
|
-
|
|
36
|
-
**How is an npm package published?**
|
|
37
|
-
Choose an available name, prepare metadata and files, run tests and npm pack --dry-run, log in with npm login, then run npm publish --access public. Complete required authentication prompts and verify the registry version and a fresh install. This project's publication is pending login; do not claim it is already published.
|
|
38
|
-
|
|
39
|
-
**What is version 1.0.0?**
|
|
40
|
-
It is the first working release. Semantic versioning uses major.minor.patch: breaking API changes increase major, compatible features increase minor, and compatible fixes increase patch.
|
|
41
|
-
|
|
42
|
-
**What do CLI exit codes mean?**
|
|
43
|
-
Zero means the audit found no issues; one means findings were detected; two means an input or command error. Other scripts can use these statuses.
|
|
44
|
-
|
|
45
|
-
**What are the limitations?**
|
|
46
|
-
The package sees only supplied declarations. It does not discover routes or verify middleware, authentication, authorization, or overall security. Paths are compared exactly; it does not understand Express routing semantics.
|
|
47
|
-
|
|
48
|
-
**How would you demonstrate reuse?**
|
|
49
|
-
Install the archive in an empty project, require permission-gap-detector, call auditRoutes with a route array, and show the summary. Then run the installed CLI on the same route data.
|
|
50
|
-
|
|
51
|
-
**What is the approximate algorithmic cost?**
|
|
52
|
-
Validation and permission checks visit each entry once. Grouping uses a Map; checking policies visits each group entry once. Typical time and memory are linear in the number of definitions, with string handling also depending on path length.
|