Skip to content

Latest commit

 

History

History
222 lines (160 loc) · 8.98 KB

AGENTS.md

File metadata and controls

222 lines (160 loc) · 8.98 KB

AGENTS.md

Working agreement for automated agents and contributors making changes in this repository. It exists so a change lands green on the first CI run instead of the third.

Read CLAUDE.md for the architecture and CONTRIBUTING.md for the human-facing summary. This file is the mechanical checklist.

Non-negotiables

CI enforces every rule in this section. .github/workflows/pr-requirements.yml runs AbsaOSS/check-pr-requirements on every PR event, so a PR that violates a rule is red before any code is looked at.

Branch name

^(feat|feature|fix|bugfix|hotfix|release|support|chore|docs|ci|test|dependabot)/[a-zA-Z0-9._/-]+$

Branch off master. master is the only allowed target branch.

Examples: fix/build-pipeline-hardening, docs/agents-guide, chore/asset-copy.

The branch prefixes are not the same set as the commit/PR title types. perf, refactor, style, build and revert are valid title types but invalid branch prefixes — a perf/… branch fails the check. Use chore/… (or fix/…) for that work and keep the perf: prefix in the title.

PR title — Conventional Commits

<type>: <summary>

Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert. A scope is optional (fix(build): …).

PR description

  • At least 20 characters. A one-word body fails.
  • Must reference an issue. Use a closing keyword so the issue is resolved on merge: Closes #42. Reference every issue an aggregated PR resolves, each on its own line.

Template that satisfies the checker:

## What

One paragraph on what changed and why.

## Changes

- `path/to/file.js` — what and why

## Verification

- `npm run build:headless` — green
- `npm test` — green
- `npx playwright test --config=playwright.config.ci.js` — green

Closes #42
Closes #43

Size

Maximum 50 changed files per PR. Split larger work.

Commits

Conventional Commits, same type list as PR titles. Keep the subject under ~72 characters and explain why in the body when it is not obvious from the diff.

Before opening a PR

All three must pass locally — CI runs the same three:

npm run build:headless                                  # hermetic build
npm test                                                # embedded web-fragment E2E
npx playwright test --config=playwright.config.ci.js    # standalone fragment layer

The build and both suites are hermetic: they use the committed tests/fixtures/ artifacts via apps.json, so no GITHUB_TOKEN, no network and no sibling repository is required. If a change makes any of them need network, that is the bug — fix the change, not the test.

A fourth suite needs Docker and is therefore not part of npm test:

npm run test:container   # integration tests against the real nginx image

Run it when touching nginx.conf, nginx.headers.conf or the Dockerfile. It is the only place the shipped config is executed — the other suites run against tests/fragment-server.mjs, an Express mirror of the nginx rewrites. That mirror is a second implementation of the same contract and it has drifted twice (#45, #60), so a change to nginx behaviour means changing both, and proving it with this suite. CI runs it inside the image job, which already builds the image.

Locally it sets reuseExistingServer, so a container left running from an earlier run answers on :8099 and the suite passes against the old dist/. Before trusting a green run: docker ps --filter "publish=8099", remove anything there, rebuild, then run it.

npm audit --omit=dev --audit-level=high must also stay clean; it gates CI.

Repository conventions

Hermetic by construction

apps.json is committed and CI builds from it. Entries pointing outside this repository must carry "optional": true so a fresh clone still builds. Never add a registry entry that requires network or a sibling checkout without it.

Lockfiles name no registry

package-lock.json and actions/package-lock.json carry a version and an integrity hash per package but no resolved URL: the committed .npmrc next to each sets omit-lockfile-registry-resolved=true. npm then fetches from whichever registry is configured at install time — registry.npmjs.org, or an internal mirror on a private network — and the hash still pins the tarball. A lockfile regenerated behind a corporate ~/.npmrc therefore stays portable, no --registry flag needed. Keep both .npmrc files; tests/private-registry.spec.js fails if either loses the setting or a lockfile gains a registry URL.

Two build modes, one document

Every page renders through src/layouts/Base.astro. Headless (web-fragment) and standalone differ only by data-kb-headless and the shadow-DOM compat styles — not by a different layout. Changes that add a mode-specific code path need a strong reason.

Light only

The knowledge base has no dark mode: no theme toggle, no persisted theme, no dark class, no dark palette. A sub-app's own theme bootstrap is removed twice: scripts/hoist-inline-scripts.js deletes it while it is still inline, and src/utils/transform.js strips any that survives, along with a dark body class. Do not reintroduce any of it, and keep both halves — hoisting a bootstrap instead of deleting it puts it beyond the reach of the transform.

The knowledge base's CSS is inlined; a sub-app's is layered

Inside a web fragment the <head> belongs to reframed, which has lost, moved and duplicated head <link>/<style> nodes across ClientRouter swaps (web-fragments #297). So the knowledge base stylesheet is never linked from <head>: src/layouts/Base.astro inlines it into every <body>, where it is replaced together with the page. And every sub-app stylesheet — CSS files in scripts/build-vite.js, inline <style> blocks in src/utils/transform.js — is wrapped in the kb-app cascade layer, below the knowledge base's own rules, with the masthead and the catalog (.kb-shell) fenced by all: revert in the kb-reset layer. A sub-app sheet that outlives its page can then not restyle them. src/utils/css-layers.js owns the order and the wrapper; keep all three emitters of the order statement (layout head, rewritten sub-app CSS, knowledge-base.css) in agreement, and do not reintroduce a <link> to the knowledge base CSS — tests/build-integrity.spec.js and tests/css-isolation.spec.js fail if you do.

Sub-app HTML is untrusted input

Artifacts come from other repositories' releases. Treat their HTML, CSS and archive contents as attacker-controlled: no unvalidated archive extraction, no unsanitised HTML re-hosting, no shell interpolation of registry values.

Nothing inline in the output

The deployment serves script-src 'self' with no 'unsafe-inline'. That holds only because no inline <script> survives into dist/ — the publishing action emits its mermaid init as a file, and scripts/hoist-inline-scripts.js moves any inline script found in a sub-app artifact into one. A change that introduces an inline script fails tests/build-integrity.spec.js before it can start breaking pages silently in production.

The check covers <script> elements. Inline on* handlers are a known gap (#67): they are equally blocked by the policy but nothing strips or reports them.

Inline <style> is allowed (style-src keeps 'unsafe-inline') and now relied on: the knowledge base stylesheet itself is an inline block in every body (see above). Tightening style-src would mean hashes or nonces for it, not dropping it.

Portability

The build runs on Linux CI and on Windows developer machines. Prefer Node APIs (cpSync, rmSync) over shelling out to cp/rm. Where tar is unavoidable, follow the drive-letter workaround documented in scripts/artifacts.js (stageArtifact).

The repository has no .gitattributes, so a Windows checkout is CRLF. Two consequences: git status reports apps.json and the generated fixtures as modified when only line endings changed — check git diff --stat, which will show nothing, before staging — and a $-anchored regex over file text will not match, because . does not match \r.

Contract changes

contract/ is the public API for onboarding repositories. Changing schema.json, HEADLESS_RULES.md, STYLE_GUIDE.md or SINGLE_PAGE.md is a breaking change for every doc app — call it out explicitly in the PR description.

Pinning

Every GitHub Action is pinned to a commit SHA with the version in a trailing comment. Keep it that way; Dependabot bumps them.

Aggregated PRs

Grouping related issues into one PR is fine and often better than a chain of one-line PRs. When doing so:

  • Group by subsystem, not by severity — reviewers read one area at a time.
  • Reference every issue with its own Closes #N line.
  • Keep the diff under the 50-file limit.
  • Do not mix a security fix with an unrelated refactor; a reviewer should be able to reason about the security change in isolation.