openpitstop 1.0.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/LICENSE +21 -0
- package/README.md +512 -0
- package/demo-repo/README.md +24 -0
- package/demo-repo/package-lock.json +4483 -0
- package/demo-repo/package.json +17 -0
- package/demo-repo/src/config.js +5 -0
- package/demo-repo/src/db.js +31 -0
- package/demo-repo/src/server.js +13 -0
- package/demo-repo/src/userController.js +22 -0
- package/demo-repo/src/userRepo.js +18 -0
- package/demo-repo/src/userService.js +59 -0
- package/demo-repo/test/user.test.js +12 -0
- package/demo-repo-fintech/README.md +27 -0
- package/demo-repo-fintech/package-lock.json +1023 -0
- package/demo-repo-fintech/package.json +14 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-conc-1-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-retry-2-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/pitstop-repro-ledger-order-ord-webhook-3-charged-2.test.mjs +175 -0
- package/demo-repo-fintech/src/gateway.js +26 -0
- package/demo-repo-fintech/src/server.js +61 -0
- package/demo-repo-generators/package-lock.json +1508 -0
- package/demo-repo-generators/package.json +17 -0
- package/demo-repo-generators/public/index.html +10 -0
- package/demo-repo-generators/scripts/build.js +17 -0
- package/demo-repo-generators/src/counter.js +16 -0
- package/demo-repo-integrity/README.md +49 -0
- package/demo-repo-integrity/package.json +12 -0
- package/demo-repo-integrity/src/money.js +19 -0
- package/demo-repo-integrity/test/money.test.js +17 -0
- package/dist/analyzers/accessibility.d.ts +18 -0
- package/dist/analyzers/accessibility.js +248 -0
- package/dist/analyzers/accessibility.js.map +1 -0
- package/dist/analyzers/dependencyGraph.d.ts +14 -0
- package/dist/analyzers/dependencyGraph.js +206 -0
- package/dist/analyzers/dependencyGraph.js.map +1 -0
- package/dist/analyzers/devex.d.ts +19 -0
- package/dist/analyzers/devex.js +301 -0
- package/dist/analyzers/devex.js.map +1 -0
- package/dist/analyzers/duplication.d.ts +2 -0
- package/dist/analyzers/duplication.js +47 -0
- package/dist/analyzers/duplication.js.map +1 -0
- package/dist/analyzers/index.d.ts +12 -0
- package/dist/analyzers/index.js +38 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.d.ts +2 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.js +164 -0
- package/dist/analyzers/integrity/assertionLiteralTamper.js.map +1 -0
- package/dist/analyzers/integrity/exceptionSwallow.d.ts +2 -0
- package/dist/analyzers/integrity/exceptionSwallow.js +198 -0
- package/dist/analyzers/integrity/exceptionSwallow.js.map +1 -0
- package/dist/analyzers/integrity/exitCheat.d.ts +2 -0
- package/dist/analyzers/integrity/exitCheat.js +31 -0
- package/dist/analyzers/integrity/exitCheat.js.map +1 -0
- package/dist/analyzers/integrity/git.d.ts +10 -0
- package/dist/analyzers/integrity/git.js +181 -0
- package/dist/analyzers/integrity/git.js.map +1 -0
- package/dist/analyzers/integrity/hardcodedMatch.d.ts +2 -0
- package/dist/analyzers/integrity/hardcodedMatch.js +93 -0
- package/dist/analyzers/integrity/hardcodedMatch.js.map +1 -0
- package/dist/analyzers/integrity/helpers.d.ts +21 -0
- package/dist/analyzers/integrity/helpers.js +66 -0
- package/dist/analyzers/integrity/helpers.js.map +1 -0
- package/dist/analyzers/integrity/index.d.ts +10 -0
- package/dist/analyzers/integrity/index.js +27 -0
- package/dist/analyzers/integrity/index.js.map +1 -0
- package/dist/analyzers/integrity/mockOverreach.d.ts +2 -0
- package/dist/analyzers/integrity/mockOverreach.js +72 -0
- package/dist/analyzers/integrity/mockOverreach.js.map +1 -0
- package/dist/analyzers/integrity/suppressionCreep.d.ts +2 -0
- package/dist/analyzers/integrity/suppressionCreep.js +27 -0
- package/dist/analyzers/integrity/suppressionCreep.js.map +1 -0
- package/dist/analyzers/integrity/testTamper.d.ts +2 -0
- package/dist/analyzers/integrity/testTamper.js +153 -0
- package/dist/analyzers/integrity/testTamper.js.map +1 -0
- package/dist/analyzers/integrity/types.d.ts +63 -0
- package/dist/analyzers/integrity/types.js +13 -0
- package/dist/analyzers/integrity/types.js.map +1 -0
- package/dist/analyzers/ledger/attacks.d.ts +17 -0
- package/dist/analyzers/ledger/attacks.js +135 -0
- package/dist/analyzers/ledger/attacks.js.map +1 -0
- package/dist/analyzers/ledger/discover.d.ts +15 -0
- package/dist/analyzers/ledger/discover.js +122 -0
- package/dist/analyzers/ledger/discover.js.map +1 -0
- package/dist/analyzers/ledger/evidence.d.ts +22 -0
- package/dist/analyzers/ledger/evidence.js +127 -0
- package/dist/analyzers/ledger/evidence.js.map +1 -0
- package/dist/analyzers/ledger/harness.d.ts +4 -0
- package/dist/analyzers/ledger/harness.js +270 -0
- package/dist/analyzers/ledger/harness.js.map +1 -0
- package/dist/analyzers/ledger/index.d.ts +14 -0
- package/dist/analyzers/ledger/index.js +116 -0
- package/dist/analyzers/ledger/index.js.map +1 -0
- package/dist/analyzers/ledger/types.d.ts +31 -0
- package/dist/analyzers/ledger/types.js +2 -0
- package/dist/analyzers/ledger/types.js.map +1 -0
- package/dist/analyzers/perf.d.ts +2 -0
- package/dist/analyzers/perf.js +106 -0
- package/dist/analyzers/perf.js.map +1 -0
- package/dist/analyzers/reliability.d.ts +22 -0
- package/dist/analyzers/reliability.js +339 -0
- package/dist/analyzers/reliability.js.map +1 -0
- package/dist/analyzers/routes.d.ts +17 -0
- package/dist/analyzers/routes.js +115 -0
- package/dist/analyzers/routes.js.map +1 -0
- package/dist/analyzers/security.d.ts +2 -0
- package/dist/analyzers/security.js +302 -0
- package/dist/analyzers/security.js.map +1 -0
- package/dist/analyzers/suiteRunner.d.ts +64 -0
- package/dist/analyzers/suiteRunner.js +381 -0
- package/dist/analyzers/suiteRunner.js.map +1 -0
- package/dist/analyzers/tests.d.ts +2 -0
- package/dist/analyzers/tests.js +215 -0
- package/dist/analyzers/tests.js.map +1 -0
- package/dist/analyzers/types.d.ts +203 -0
- package/dist/analyzers/types.js +2 -0
- package/dist/analyzers/types.js.map +1 -0
- package/dist/analyzers/util.d.ts +35 -0
- package/dist/analyzers/util.js +209 -0
- package/dist/analyzers/util.js.map +1 -0
- package/dist/ciCheckA.d.ts +2 -0
- package/dist/ciCheckA.js +5 -0
- package/dist/ciCheckA.js.map +1 -0
- package/dist/ciCheckB.d.ts +2 -0
- package/dist/ciCheckB.js +6 -0
- package/dist/ciCheckB.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/budget.d.ts +33 -0
- package/dist/commands/budget.js +108 -0
- package/dist/commands/budget.js.map +1 -0
- package/dist/commands/ci.d.ts +14 -0
- package/dist/commands/ci.js +157 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/demo.d.ts +2 -0
- package/dist/commands/demo.js +163 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/digest.d.ts +8 -0
- package/dist/commands/digest.js +189 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +98 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/drive.d.ts +3 -0
- package/dist/commands/drive.js +170 -0
- package/dist/commands/drive.js.map +1 -0
- package/dist/commands/gate.d.ts +2 -0
- package/dist/commands/gate.js +136 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/honesty.d.ts +2 -0
- package/dist/commands/honesty.js +182 -0
- package/dist/commands/honesty.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +244 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +81 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/integrity.d.ts +2 -0
- package/dist/commands/integrity.js +74 -0
- package/dist/commands/integrity.js.map +1 -0
- package/dist/commands/memory.d.ts +6 -0
- package/dist/commands/memory.js +90 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/pen.d.ts +17 -0
- package/dist/commands/pen.js +158 -0
- package/dist/commands/pen.js.map +1 -0
- package/dist/commands/prompt.d.ts +2 -0
- package/dist/commands/prompt.js +37 -0
- package/dist/commands/prompt.js.map +1 -0
- package/dist/commands/readyCheck.d.ts +21 -0
- package/dist/commands/readyCheck.js +68 -0
- package/dist/commands/readyCheck.js.map +1 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +48 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/repro.d.ts +3 -0
- package/dist/commands/repro.js +61 -0
- package/dist/commands/repro.js.map +1 -0
- package/dist/commands/scan.d.ts +27 -0
- package/dist/commands/scan.js +348 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/share.d.ts +2 -0
- package/dist/commands/share.js +163 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/trends.d.ts +2 -0
- package/dist/commands/trends.js +103 -0
- package/dist/commands/trends.js.map +1 -0
- package/dist/commands/try.d.ts +12 -0
- package/dist/commands/try.js +208 -0
- package/dist/commands/try.js.map +1 -0
- package/dist/commands/verify.d.ts +44 -0
- package/dist/commands/verify.js +381 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.js +70 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/evidence.d.ts +37 -0
- package/dist/evidence.js +61 -0
- package/dist/evidence.js.map +1 -0
- package/dist/graph/correlate.d.ts +7 -0
- package/dist/graph/correlate.js +246 -0
- package/dist/graph/correlate.js.map +1 -0
- package/dist/graph/integrity.d.ts +22 -0
- package/dist/graph/integrity.js +39 -0
- package/dist/graph/integrity.js.map +1 -0
- package/dist/installer/targets.d.ts +23 -0
- package/dist/installer/targets.js +162 -0
- package/dist/installer/targets.js.map +1 -0
- package/dist/memory/store.d.ts +33 -0
- package/dist/memory/store.js +131 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/pen/dynamic.d.ts +36 -0
- package/dist/pen/dynamic.js +622 -0
- package/dist/pen/dynamic.js.map +1 -0
- package/dist/pen/fix.d.ts +35 -0
- package/dist/pen/fix.js +239 -0
- package/dist/pen/fix.js.map +1 -0
- package/dist/pen/proof.d.ts +46 -0
- package/dist/pen/proof.js +112 -0
- package/dist/pen/proof.js.map +1 -0
- package/dist/pen/report.d.ts +11 -0
- package/dist/pen/report.js +258 -0
- package/dist/pen/report.js.map +1 -0
- package/dist/pen/static.d.ts +17 -0
- package/dist/pen/static.js +565 -0
- package/dist/pen/static.js.map +1 -0
- package/dist/pen/store.d.ts +11 -0
- package/dist/pen/store.js +36 -0
- package/dist/pen/store.js.map +1 -0
- package/dist/pen/types.d.ts +112 -0
- package/dist/pen/types.js +53 -0
- package/dist/pen/types.js.map +1 -0
- package/dist/report/format.d.ts +126 -0
- package/dist/report/format.js +706 -0
- package/dist/report/format.js.map +1 -0
- package/dist/report/score.d.ts +47 -0
- package/dist/report/score.js +164 -0
- package/dist/report/score.js.map +1 -0
- package/dist/repro/framework.d.ts +26 -0
- package/dist/repro/framework.js +224 -0
- package/dist/repro/framework.js.map +1 -0
- package/dist/repro/generate.d.ts +14 -0
- package/dist/repro/generate.js +669 -0
- package/dist/repro/generate.js.map +1 -0
- package/dist/repro/ids.d.ts +32 -0
- package/dist/repro/ids.js +175 -0
- package/dist/repro/ids.js.map +1 -0
- package/dist/repro/index.d.ts +24 -0
- package/dist/repro/index.js +69 -0
- package/dist/repro/index.js.map +1 -0
- package/dist/repro/pen.d.ts +26 -0
- package/dist/repro/pen.js +321 -0
- package/dist/repro/pen.js.map +1 -0
- package/dist/repro/run.d.ts +18 -0
- package/dist/repro/run.js +36 -0
- package/dist/repro/run.js.map +1 -0
- package/dist/sandbox/proxy.d.ts +41 -0
- package/dist/sandbox/proxy.js +231 -0
- package/dist/sandbox/proxy.js.map +1 -0
- package/dist/sandbox/startCmd.d.ts +24 -0
- package/dist/sandbox/startCmd.js +71 -0
- package/dist/sandbox/startCmd.js.map +1 -0
- package/dist/ui/spinner.d.ts +18 -0
- package/dist/ui/spinner.js +26 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/verify/metrics.d.ts +13 -0
- package/dist/verify/metrics.js +72 -0
- package/dist/verify/metrics.js.map +1 -0
- package/package.json +68 -0
- package/scripts/cheat-demo.cjs +102 -0
- package/templates/ledger/preload.cjs +331 -0
- package/templates/pen/preload.cjs +196 -0
- package/templates/pitstop.prompt.md +371 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pitstop-demo-api",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "OpenPitStop's intentionally-broken demo API",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node src/server.js",
|
|
8
|
+
"test": "jest"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"express": "^4.18.2",
|
|
12
|
+
"lodash": "4.17.15"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"jest": "^29.7.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Fake in-memory data layer. In a real app this would open a DB connection.
|
|
2
|
+
const users = [
|
|
3
|
+
{ id: 1, name: "alice", email: "alice@example.com", score: 70 },
|
|
4
|
+
{ id: 2, name: "bob", email: "bob@example.com", score: 30 },
|
|
5
|
+
{ id: 3, name: "carol", email: "carol@example.com", score: 10 },
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
const posts = [
|
|
9
|
+
{ id: 101, userId: 1, title: "Hello" },
|
|
10
|
+
{ id: 102, userId: 1, title: "World" },
|
|
11
|
+
{ id: 103, userId: 2, title: "Hi" },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function query(sql, params) {
|
|
15
|
+
// Pretend this hits the database.
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getUsers() {
|
|
20
|
+
return users;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getPostsByUser(userId) {
|
|
24
|
+
return posts.filter((p) => p.userId === userId);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getConnection() {
|
|
28
|
+
return { query };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = { query, getUsers, getPostsByUser, getConnection };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const express = require("express");
|
|
2
|
+
const userController = require("./userController");
|
|
3
|
+
|
|
4
|
+
const app = express();
|
|
5
|
+
|
|
6
|
+
app.get("/users", userController.list);
|
|
7
|
+
|
|
8
|
+
if (require.main === module) {
|
|
9
|
+
const port = process.env.PORT || 3000;
|
|
10
|
+
app.listen(port, () => console.log(`pitstop-demo-api listening on ${port}`));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = app;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const service = require("./userService");
|
|
2
|
+
const db = require("./db");
|
|
3
|
+
|
|
4
|
+
function list(req, res) {
|
|
5
|
+
const users = service.listUsersWithPosts();
|
|
6
|
+
res.json(users);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function render(users) {
|
|
10
|
+
// --- DUPLICATED BLOCK (start) ---
|
|
11
|
+
return users.map((u) => {
|
|
12
|
+
const name = (u.name || "").toUpperCase();
|
|
13
|
+
const email = (u.email || "").toLowerCase();
|
|
14
|
+
const score = (u.score || 0) + 10;
|
|
15
|
+
const tier = score > 50 ? "gold" : score > 20 ? "silver" : "bronze";
|
|
16
|
+
const summary = `${name} <${email}> [${tier}]`;
|
|
17
|
+
return { id: u.id, summary, score };
|
|
18
|
+
});
|
|
19
|
+
// --- DUPLICATED BLOCK (end) ---
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { list, render };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const db = require("./db");
|
|
2
|
+
// Intentional layering violation: the repository reaches back up to the service.
|
|
3
|
+
const userService = require("./userService");
|
|
4
|
+
|
|
5
|
+
function getUsers() {
|
|
6
|
+
return db.getUsers();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function getPostsByUser(userId) {
|
|
10
|
+
return db.getPostsByUser(userId);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getUserSummary(id) {
|
|
14
|
+
const u = db.getUsers().find((x) => x.id === id);
|
|
15
|
+
return userService.formatUser(u);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { getUsers, getPostsByUser, getUserSummary };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const _ = require("lodash");
|
|
2
|
+
const repo = require("./userRepo");
|
|
3
|
+
// Intentional circular dependency: the service reaches into the controller.
|
|
4
|
+
const controller = require("./userController");
|
|
5
|
+
const config = require("./config");
|
|
6
|
+
|
|
7
|
+
// BUG: tier calculation is missing the "silver" band.
|
|
8
|
+
function calculateTier(score) {
|
|
9
|
+
if (score > 100) return "gold";
|
|
10
|
+
return "bronze";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// BUG: should uppercase the name but does nothing.
|
|
14
|
+
function normalizeName(name) {
|
|
15
|
+
return name;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function formatUser(u) {
|
|
19
|
+
return { id: u.id, name: u.name, email: u.email };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// N+1 query pattern: fetch all users, then one query per user for their posts.
|
|
23
|
+
// Spans userController -> userService -> userRepo (3 files).
|
|
24
|
+
function listUsersWithPosts() {
|
|
25
|
+
const users = repo.getUsers();
|
|
26
|
+
for (const u of users) {
|
|
27
|
+
u.posts = repo.getPostsByUser(u.id);
|
|
28
|
+
}
|
|
29
|
+
return users;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function summarize(users) {
|
|
33
|
+
// --- DUPLICATED BLOCK (start) ---
|
|
34
|
+
return users.map((u) => {
|
|
35
|
+
const name = (u.name || "").toUpperCase();
|
|
36
|
+
const email = (u.email || "").toLowerCase();
|
|
37
|
+
const score = (u.score || 0) + 10;
|
|
38
|
+
const tier = score > 50 ? "gold" : score > 20 ? "silver" : "bronze";
|
|
39
|
+
const summary = `${name} <${email}> [${tier}]`;
|
|
40
|
+
return { id: u.id, summary, score };
|
|
41
|
+
});
|
|
42
|
+
// --- DUPLICATED BLOCK (end) ---
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function renderList() {
|
|
46
|
+
const users = listUsersWithPosts();
|
|
47
|
+
// The API key is "used" here only to make the config import reachable.
|
|
48
|
+
void config.API_KEY;
|
|
49
|
+
return controller.render(users);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
calculateTier,
|
|
54
|
+
normalizeName,
|
|
55
|
+
formatUser,
|
|
56
|
+
listUsersWithPosts,
|
|
57
|
+
summarize,
|
|
58
|
+
renderList,
|
|
59
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const service = require("../src/userService");
|
|
2
|
+
|
|
3
|
+
describe("pitstop-demo-api", () => {
|
|
4
|
+
it("assigns the correct tier for a mid score", () => {
|
|
5
|
+
// score 30 -> +10 = 40 -> should be "silver"
|
|
6
|
+
expect(service.calculateTier(30)).toBe("silver");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("uppercases the name", () => {
|
|
10
|
+
expect(service.normalizeName("bob")).toBe("BOB");
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# pitstop-demo-fintech
|
|
2
|
+
|
|
3
|
+
> **This is OpenPitStop's intentionally-broken *fintech* demo repository.** It is the
|
|
4
|
+
> companion fixture for `pitstop scan --ledger`, whose job is to prove a **real
|
|
5
|
+
> double-charge** exists (not a simulated one).
|
|
6
|
+
|
|
7
|
+
## What's broken (on purpose)
|
|
8
|
+
|
|
9
|
+
- `POST /api/orders/:id/charge` — takes `amount`/`currency` and an optional
|
|
10
|
+
`Idempotency-Key` header, forwards a real charge to the (mocked) `razorpay`
|
|
11
|
+
gateway… but **never dedupes on the idempotency key**. Fire the same key twice
|
|
12
|
+
and the gateway is charged twice.
|
|
13
|
+
- `POST /api/webhooks/razorpay` — on every `payment.captured` event it captures
|
|
14
|
+
the payment through the gateway with **no dedup**. Replay the same webhook and
|
|
15
|
+
the gateway is captured twice.
|
|
16
|
+
|
|
17
|
+
## Safety
|
|
18
|
+
|
|
19
|
+
`pitstop scan --ledger` runs this app under a `nock` sandbox that intercepts
|
|
20
|
+
*every* outbound HTTP request before it leaves the process. The `razorpay`
|
|
21
|
+
requests land on a local mock and **never** reach a real payment gateway.
|
|
22
|
+
|
|
23
|
+
Run it (from the repo root):
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
node dist/cli.js scan demo-repo-fintech --ledger
|
|
27
|
+
```
|