Skip to content
Closed
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
70 changes: 70 additions & 0 deletions .github/workflows/schema-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: ProseMirror Schema Check

# Fails when schemas/prosemirror/ is out of date — i.e. an editor extension
# change (or a TipTap dependency bump) landed without a regenerated schema.
# The export is byte-deterministic, so a plain diff is a reliable check.
# See schemas/prosemirror/README.md.

on:
pull_request:
push:
branches:
- main
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
schema-drift:
runs-on: ubuntu-latest
env:
TIPTAP_PRO_TOKEN: ${{ secrets.TIPTAP_PRO_TOKEN }}
FONTAWESOME_NPM_AUTH_TOKEN: ${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
Comment on lines +22 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep registry tokens away from pull-request scripts

For same-repository pull requests, these job-wide secrets remain available after checkout while both npm ci and the PR-controlled schema:export script execute, so a contributor can alter prepare, the export script, or an imported module to transmit both private-registry credentials. This is not limited to explicit export code: npm documents that npm ci runs install and prepare lifecycle scripts. Install with scripts disabled and ensure the environment variables and generated .npmrc are removed before executing any code from the pull request.

Useful? React with 👍 / 👎.

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Check registry secrets
run: |
if [ -z "$TIPTAP_PRO_TOKEN" ] || [ -z "$FONTAWESOME_NPM_AUTH_TOKEN" ]; then
echo "::error::Missing TIPTAP_PRO_TOKEN and/or FONTAWESOME_NPM_AUTH_TOKEN repo secrets; npm ci needs them for the private TipTap Pro and Font Awesome registries."
exit 1
fi

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm

# Same registry mapping developers keep in their local .npmrc; the
# ${VAR} references are expanded by npm itself from the job env.
- name: Configure private npm registries
run: |
{
echo '@tiptap-pro:registry=https://registry.tiptap.dev/'
echo '//registry.tiptap.dev/:_authToken=${TIPTAP_PRO_TOKEN}'
echo '@awesome.me:registry=https://npm.fontawesome.com/'
echo '@fortawesome:registry=https://npm.fontawesome.com/'
echo '//npm.fontawesome.com/:_authToken=${FONTAWESOME_NPM_AUTH_TOKEN}'
} > .npmrc

- name: Install dependencies
run: npm ci

Check warning on line 55 in .github/workflows/schema-check.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Omitting "--ignore-scripts" allows lifecycle scripts to run during package installation.

See more on https://sonarcloud.io/project/issues?id=ResearchHub_web&issues=AaAaUu7i2jZicE74bnm6&open=AaAaUu7i2jZicE74bnm6&pullRequest=1046

- name: Export ProseMirror schemas
run: npm run schema:export

- name: Fail on schema drift
run: |
if [ -n "$(git status --porcelain -- schemas/prosemirror/)" ]; then
echo '::error::schemas/prosemirror/ is out of date. Run `npm run schema:export` and commit the result (see schemas/prosemirror/README.md).'
echo
echo 'Drift:'
git status --porcelain -- schemas/prosemirror/
git diff -- schemas/prosemirror/
exit 1
fi
echo 'Schemas are up to date.'
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
"prettier --write --ignore-path .gitignore",
"eslint --fix --no-warn-ignored"
],
"**/*.{ts,tsx}": "bash -c 'npm run type-check'"
"**/*.{ts,tsx}": "bash -c 'npm run type-check'",
"{components/Editor/extensions/**/*.{ts,tsx},components/Comment/lib/**/*.{ts,tsx},scripts/export-prosemirror-schema.ts}": "bash -c 'npm run schema:export && git add schemas/prosemirror'"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stage only the generated schema files

When this hook runs while a developer has an unrelated unstaged edit under schemas/prosemirror/, such as a README change, git add schemas/prosemirror stages that edit as well and can silently include it in the extension commit. As the Git documentation notes, supplying a directory recursively adds matching files beneath it; name the two generated JSON outputs explicitly instead.

Useful? React with 👍 / 👎.

}
}
11 changes: 9 additions & 2 deletions schemas/prosemirror/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ Output is deterministic — rerunning without extension changes produces
byte-identical files. **Any change to an editor's extensions (adding,
removing, or reconfiguring — configuration can alter attribute defaults) must
be accompanied by a regenerated schema**, and the backend copy updated.
Enforcement via CI diff is a planned follow-up; until then this is by
convention.

Two layers enforce this:

- **Pre-commit**: committing a change under `components/Editor/extensions/`,
`components/Comment/lib/`, or to the export script regenerates the schemas
and stages them automatically (see `lint-staged` in `package.json`).
- **CI**: `.github/workflows/schema-check.yml` reruns the export on every PR
and fails on any diff in this directory. It also catches drift the
pre-commit globs can't see — e.g. a TipTap version bump changing a spec.

## What the export contains

Expand Down
Loading