You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 346fa7b
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+61-6Lines changed: 61 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -53,11 +53,41 @@ and is invoked through the `npm` scripts below, so you don't need to install any
53
53
|`npm run check:api:update`| Rewrites the committed API Extractor baseline `reports/api/brazilian-utils.api.md` from the current build; run it when a public signature changes on purpose and commit the new report. |
54
54
|`npm run check:commits`| Checks the commit messages since `origin/main` with commitlint (Conventional Commits). |
55
55
|`npm run check:lockfile`| Checks `package-lock.json` only resolves to the npm registry over HTTPS with integrity hashes (lockfile-lint). |
56
+
|`npm run check:vex`| Checks that every advisory suppressed for `audit-ci` and OSV-Scanner has a `not_affected` statement in `openvex.json`, and nothing else does. |
56
57
57
58
Before opening a pull request, make sure `npm run check` and `npm run test` both pass locally. If your
58
59
change touches runtime behavior, also consider running the Bun/Deno scripts above. The library is
59
60
tested and must keep working on Node.js, Bun, Deno and in browsers.
60
61
62
+
## Architecture
63
+
64
+
The library is a flat collection of pure functions, so there is not much architecture to learn,
65
+
but the few rules below hold everywhere:
66
+
67
+
-`src/<util>/<util>.ts` is one exported utility, next to its `<util>.test.ts`; `src/index.ts`
68
+
re-exports it and `package.json` exposes it as a subpath import, so consumers bundle only what
69
+
they call.
70
+
-`src/_internals/` holds the helpers shared between utilities (check-digit arithmetic, `mod10`/
71
+
`mod11`, TLV parsing for Pix, sanitizers). `src/_internals/constants/` holds the datasets
72
+
(banks, municipalities, CNAE, CBO, CFOP, NCM, legal natures), generated by the `scripts/`
73
+
from their official sources and refreshed by the `Update datasets` workflow through
74
+
a pull request, never edited by hand.
75
+
- Utilities are synchronous, stateless and side-effect free: input in, value out, no globals, no
76
+
environment access, no dynamic code. The two exceptions are `getAddressInfoByCep` and
77
+
`getCepInfoByAddress`, the only utilities that do I/O: they query public CEP APIs (BrasilAPI,
78
+
ViaCEP and the alternatives listed in their docs) over HTTPS through
79
+
`src/_internals/fetch-with-retry`, treat every response as untrusted input and never send anything
80
+
but the CEP or address being looked up.
81
+
- There are no runtime dependencies (see [Zero runtime dependencies](#zero-runtime-dependencies)),
82
+
so the trust boundary of the published package is this repository, its build toolchain and the
83
+
npm registry; [MAINTAINERS.md](MAINTAINERS.md) lists who can change what, and
84
+
[SECURITY.md](SECURITY.md) how a release is verified.
85
+
86
+
The actors around the code are the consumers of the npm package, the contributors (pull requests
87
+
from forks), the maintainers (review, merge, release approval) and the automation: GitHub Actions
88
+
builds, tests and publishes, Dependabot and the `Update datasets` workflow open update pull requests, and
89
+
release-please turns merged commits into releases.
90
+
61
91
## Adding a new utility
62
92
63
93
Brazilian Utils follows a consistent folder convention for every utility. To add a new one (for
@@ -248,16 +278,21 @@ export that goes missing.
248
278
- Every GitHub Action is pinned to a full commit SHA with the version in a trailing comment
249
279
(Dependabot updates both). Checkouts use `persist-credentials: false`.
250
280
- The `Security` workflow lints the workflows themselves with
251
-
[actionlint](https://github.com/rhysd/actionlint) and [zizmor](https://github.com/zizmorcore/zizmor)
252
-
and scans `package-lock.json` with [OSV-Scanner](https://google.github.io/osv-scanner/); the
253
-
`Check` workflow runs `audit-ci` and lockfile-lint on top. The `Security` workflow also runs the
281
+
[actionlint](https://github.com/rhysd/actionlint) and [zizmor](https://github.com/zizmorcore/zizmor),
282
+
scans `package-lock.json` with [OSV-Scanner](https://google.github.io/osv-scanner/) and scans the
283
+
commits of every pull request (the whole history on the weekly run) for leaked secrets with
284
+
[TruffleHog](https://github.com/trufflesecurity/trufflehog), next to GitHub's own secret scanning
285
+
and push protection; the `Check` workflow runs `audit-ci` and lockfile-lint on top, and
286
+
`npm run check:vex` keeps the advisories those two suppress accounted for in `openvex.json` (see
287
+
SECURITY.md). The `Security` workflow also runs the
254
288
[OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/brazilian-utils/javascript) on
255
289
every push to `main` and weekly: it grades the repository configuration (pinned actions, token
256
290
permissions, branch protection, code review, dependency updates, SAST) rather than the code,
257
291
publishes the score and uploads the findings to the Security tab.
258
-
- Every release run keeps `brazilian-utils.cdx.json` as a workflow artifact (`sbom-<tag>`), a
259
-
CycloneDX SBOM of the published package generated with `npm sbom` from the release tag; releases
260
-
are immutable here, so the file cannot be attached to the release itself. The package has no
292
+
- Every release ships `brazilian-utils.cdx.json` inside the package, a CycloneDX SBOM generated
293
+
with `npm sbom` from the release tag right before staging on npm, and keeps the same file as a
294
+
workflow artifact (`sbom-<tag>`); releases are immutable here, so the file cannot be attached to
295
+
the release itself. The package has no
261
296
runtime dependencies, so the document describes the package itself; it exists for consumers
262
297
whose supply-chain policy requires one.
263
298
- Commit messages are checked with commitlint on every pull request, since release-please derives
@@ -300,6 +335,19 @@ chore(deps-dev): bump vitest
300
335
Releases are cut from these commit types (see [Releasing](#releasing) below), so an accurate
301
336
type/scope matters.
302
337
338
+
### Developer Certificate of Origin
339
+
340
+
Every commit must carry a `Signed-off-by` line, as in the Linux kernel: it is your statement that
341
+
you wrote the change, or have the right to submit it, under the project's MIT license, per the
342
+
[Developer Certificate of Origin](https://developercertificate.org). Git adds the line for you:
343
+
344
+
```bash
345
+
git commit -s
346
+
```
347
+
348
+
`git commit -s --amend` (or `git rebase --signoff main`) fixes a commit that is missing it. Use a
349
+
real name and an e-mail address that reaches you; GitHub's `noreply` address is fine.
350
+
303
351
## Breaking changes
304
352
305
353
This library is used in production by many projects, so please do not introduce breaking changes
@@ -350,6 +398,13 @@ No local `npm login`/`npm publish` or tagging is ever needed to cut a release.
350
398
6. Open a pull request against `main` using a Conventional Commit-style title. Fill in the pull
351
399
request template checklist.
352
400
401
+
## Governance
402
+
403
+
[MAINTAINERS.md](MAINTAINERS.md) lists who maintains the project, what each role can do and how
404
+
write access is granted and removed. In short: contributors send pull requests from forks, one
405
+
maintainer reviews and merges them, the same maintainers approve releases on npm, and access grows
406
+
with a track record of merged contributions, never before.
407
+
353
408
## Recognition
354
409
355
410
We use [all-contributors](https://github.com/all-contributors/all-contributors) to recognize
0 commit comments