Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Shared with .gitattributes: LF, and a final newline, because committed artifacts are compared byte for
# byte and an editor's default is not a good reason for a fixture to differ.
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.md]
# Two trailing spaces are a hard line break in Markdown. Trimming them silently rewrites shipped prose —
# and README.md and AGENT-INSTALL.md are read by agents auditing the package.
trim_trailing_whitespace = false

[*.{lockb}]
insert_final_newline = false
trim_trailing_whitespace = false
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# One line ending in the repository, whatever a contributor's platform does locally.
#
# This matters more here than in most repositories: several committed artifacts are compared BYTE for byte
# — the vendored rule contract, the capability manifest, the canary map and rule — and CRLF slipping into
# one of them turns a cross-repository agreement check into a diff nobody can read.
* text=auto eol=lf

# Bun's binary lockfile. Marked so a diff never mangles it and `text=auto` never guesses.
*.lockb binary
100 changes: 100 additions & 0 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Bug report
description: Something in @patchstack/connect does not work as documented.
labels: [bug]
body:
- type: markdown
attributes:
value: |
**This repository is public, and so is everything you paste here.**

Before you fill this in: redact tokens, site UUIDs, customer hostnames and internal URLs. A
deleted issue is not a retracted one — it stays in notification emails, caches and forks.

Found a security vulnerability in this package? Do not file it here. Contact Patchstack directly so
it can be fixed before it is described in public.

- type: input
id: connect-version
attributes:
label: "@patchstack/connect version"
description: "`npm ls @patchstack/connect --depth=0` in your project, or the version in your lockfile."
placeholder: "0.3.31"
validations:
required: true

- type: input
id: node-version
attributes:
label: Node version
description: "`node --version`. Supported from 18."
placeholder: "v22.12.0"
validations:
required: true

- type: input
id: package-manager
attributes:
label: Package manager and version
description: npm, pnpm, Yarn or Bun — the resolution differs between them, and so do the bugs.
placeholder: "pnpm 9.12.0"
validations:
required: true

- type: input
id: framework
attributes:
label: Framework or runtime
description: Next.js, SvelteKit, Astro, NestJS, Fastify, Express, TanStack Start, Cloudflare Workers, Deno, Bun — and its version.
placeholder: "Next.js 15.1.0 (app router), Node runtime"
validations:
required: true

- type: input
id: os
attributes:
label: Operating system
placeholder: "macOS 15.1 (arm64) / Ubuntu 24.04 / Windows 11"
validations:
required: true

- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: The commands you ran, in order. A repository or a minimal project that shows it is worth more than a description.
placeholder: |
1. npm install --save @patchstack/connect
2. npx patchstack-connect setup
3. ...
validations:
required: true

- type: textarea
id: expected
attributes:
label: What you expected
description: And where it says so — the README, AGENT-INSTALL.md, the CLI's own output. A documented promise that is wrong is a different bug from a surprising behaviour.
validations:
required: true

- type: textarea
id: actual
attributes:
label: What happened instead
validations:
required: true

- type: textarea
id: logs
attributes:
label: Output and logs, sanitized
description: Command output, stack traces, the `patchstack:` lines. Replace tokens, site UUIDs and hostnames with placeholders.
render: shell

- type: checkboxes
id: disclosure
attributes:
label: Before you submit
options:
- label: This report contains no credentials or tokens, no customer data, no third-party proprietary material such as copied system prompts, and no private implementation details.
required: true
14 changes: 14 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Blank issues are disabled deliberately.
#
# The bug-report form asks for the versions and the reproduction that make a report actionable, and asks
# the reporter to confirm it carries nothing private. A blank issue bypasses both prompts, and this
# repository is public: the cost of a pasted log with a token or a customer hostname in it is not
# recoverable by deleting the issue.
blank_issues_enabled: false
contact_links:
- name: Security vulnerability in this package
url: https://patchstack.com/contact/
about: Do not open a public issue. Contact Patchstack directly so it can be fixed before it is described.
- name: Help with your Patchstack account, sites or billing
url: https://patchstack.com/contact/
about: Anything about your account rather than this package.
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
91 changes: 91 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Contributing to `@patchstack/connect`

The human counterpart to `AGENTS.md`. Same boundary, same verification; this one explains the setup.

## Before anything else: this repository is public

Its history, code comments, test output, commit messages and pull-request descriptions are all public, and
so is anything you paste into an issue.

`AGENTS.md` carries the boundary in full and is worth reading once. The two rules that catch people:

- **Nothing from private Patchstack systems** unless it is already in this repository's public
documentation or public API contract — no private repository names or paths, no internal topology or
endpoints, no customer or vulnerability-review data, no local filesystem paths.
- **Nothing third-party confidential**, which is a separate obligation and not a special case of the
first: copied system prompts, private transcripts, unpublished documentation. Material can be entirely
free of Patchstack internals and still not be ours to publish. Verify that something is public rather
than assuming it.

Fixtures are synthetic or explicitly public. Do not copy one from a private repository to make a test more
realistic — write it.

## Setup

```bash
# .node-version records the version releases are built with (24). fnm, nodenv and asdf read it directly;
# nvm looks for .nvmrc, so it needs the file passed in.
nvm use "$(cat .node-version)" # or: fnm use / nodenv local
npm ci
```

Consumers are supported from Node 18 — `engines.node` is that contract, and it is a different question
from the version this repository is developed and released on.

## The loop

```bash
npm run typecheck # tsc --noEmit, plus the guard templates, which are typechecked separately
npm run build # tsup -> dist/ (gitignored; built on publish)
npm test # vitest
```

Build before testing, in that order. `dist/` is not committed, and several tests only run once it exists —
they skip in a plain checkout and are required in CI. Run in the other order and those tests skip, which
reads exactly like passing.

## Before you open a pull request

- `npm run typecheck`, `npm test`, `npm run build` all clean.
- `npm pack --dry-run` if you touched anything about packaging. `files` in `package.json` is the
authoritative allowlist of what ships.
- Read your own diff, commit messages and pull-request description against the boundary above. The
pull-request template asks you to confirm this; it is the only control that covers prose, because secret
scanning finds credentials and nothing finds a paragraph of architecture.

Changing onboarding, the install prompt or the setup guide? Read `MAINTAINING.md` first — it maps which
files are load-bearing — and note that the install prompt is a tested artifact with its own gate in
`field-test/`.

## Generated artifacts that must stay in step

Each of these is generated from a source of truth and committed. Changing the source without regenerating
leaves two files disagreeing, and the check that notices is not always the one that fails first:

| artifact | generated from | regenerate with |
|---|---|---|
| `capabilities.json` | `src/map/capabilities.ts` | `node scripts/emit-capabilities.mjs` |
| `rule-contract.json` | the engine's match types and actions | `npm run rule-contract` |
| the canary attack-surface map | `tests/map/canary-case.ts` | `PS_CANARY_EMIT_DIR=<dir> npx vitest run tests/map/canary-emit` |

A vocabulary change to `capabilities.json` also needs `CAPABILITY_VERSION` moved. `npm run
capabilities:check` and `npm run rule-contract:check` are what CI runs.

## Comments and prose

- Comments describe the code that is there and the invariant it holds — not the code that used to be, and
not how a fix was reasoned about.
- **The same applies to a pull-request description**, which is public. State what changed and the
externally observable reason it matters. "What used to happen", "how we found it" and the mutations you
tried belong in the private engineering record, not here — see the boundary in `AGENTS.md`.
- No ticket references anywhere in the tree. They go in the pull-request title and description.
- Plain words, short sentences. Lead with what changed and why it matters.

## Reporting a bug

Use the bug-report form, which asks for the versions and the reproduction that make a report actionable —
and asks you to confirm it carries no credentials, customer data or private implementation details. If a
report cannot be written without those, contact Patchstack support instead of filing it here.

Think you have found a security vulnerability in this package? Do not open an issue — see `SECURITY.md`
if present, or contact Patchstack support directly.
19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
{
"name": "@patchstack/connect",
"version": "0.3.6",
"description": "Patchstack connector for JavaScript applications. Scans your lockfile and reports installed packages to Patchstack for vulnerability monitoring.",
"description": "Runtime application security for JavaScript and Node.js: dependency inventory, attack-surface mapping, and an in-process guard that virtually patches known vulnerabilities and hardens responses.",
"keywords": [
"patchstack",
"security",
"application-security",
"nodejs-security",
"runtime-security",
"rasp",
"virtual-patching",
"waf",
"vulnerability",
"cve",
"npm-audit",
"sca",
"dependency-scanning"
"dependency-scanning",
"npm-audit",
"attack-surface",
"ssrf",
"secret-redaction"
],
"license": "MIT",
"type": "module",
Expand Down Expand Up @@ -61,6 +70,10 @@
"engines": {
"node": ">=18"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"devDependencies": {
"@types/node": "^20.11.0",
"fastify": "^5.12.1",
Expand Down
Loading