Skip to content

ci: add build + typecheck workflow and fix link-check Node version - #115

Merged
idanlodzki merged 1 commit into
mainfrom
ci/build-and-typecheck
Aug 1, 2026
Merged

ci: add build + typecheck workflow and fix link-check Node version#115
idanlodzki merged 1 commit into
mainfrom
ci/build-and-typecheck

Conversation

@idanlodzki

@idanlodzki idanlodzki commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Why

Nothing in CI builds or typechecks this repo. A PR can go green and still be broken — and one currently is: #113 (TypeScript 7) passes Vercel but fails npm run typecheck, because the Docusaurus build never invokes tsc. Without this workflow there's no signal that would have caught it.

What

A CI workflow that runs on every PR and push to main:

  1. npm ci (root workspace)
  2. npm run typecheck in opsimate-docs
  3. npm run build

Both steps verified locally against current main — typecheck clean, build succeeds.

Also fixed: link-check has been broken for ~3 months

The existing link-check.yml has been failing every scheduled run, at the Build documentation step. Cause:

.github/workflows/link-check.yml:31   node-version: '18'
@docusaurus/core 3.10                 engines.node: >=20.0

It pins Node 18, which Docusaurus refuses to run on — so the build step could never pass, and the link check that depends on it never ran at all. Bumped to Node 24, matching opsimate-docs/dockerfile.

Also corrected opsimate-docs/package.json, which still declared engines.node: ">=18.0" — stale since the Docusaurus 3.10 bump and actively misleading about what this project runs on.

Note for a follow-up

There are two lockfiles — package-lock.json at the root and opsimate-docs/package-lock.json — which is unusual for an npm workspace and means the two can drift. This workflow uses the root one. Worth reconciling separately; I didn't touch it here to keep this PR reviewable.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added automated checks for code type validation and documentation builds on code changes.
    • Added support for manually triggering the validation workflow.
    • Updated the documentation environment to use Node.js 24 in automated checks.
    • Updated the minimum supported Node.js version for the documentation package from 18 to 20.

Nothing in CI built or typechecked this repo, so a PR could go green and
still be broken. Dependabot's TypeScript 7 bump (#113) is a live example:
Vercel passes it because the Docusaurus build never runs tsc, but
`npm run typecheck` fails on it with TS5102 (baseUrl removed).

Add a CI workflow running typecheck and build on every PR and push to
main.

While here: the existing link-check workflow has been failing at its
"Build documentation" step for about three months. It pins node-version
18, but @docusaurus/core 3.10 declares engines.node >=20, so the build
could never succeed. Bumped it to 24 to match opsimate-docs/dockerfile,
and corrected the stale engines.node in opsimate-docs/package.json,
which still claimed >=18.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
documentation-opsimate-docs2 Ready Ready Preview Aug 1, 2026 7:33pm

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Node.js CI alignment

Layer / File(s) Summary
Runtime requirement and workflow versions
.github/workflows/link-check.yml, opsimate-docs/package.json
The package requires Node.js >=20.0. The link-check workflow uses Node.js 24.
Continuous integration workflow
.github/workflows/ci.yml
A GitHub Actions workflow runs on pushes and pull requests targeting main, plus manual dispatches. It installs dependencies, typechecks opsimate-docs, and builds the project with Node.js 24.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@idanlodzki
idanlodzki merged commit 7feb6ce into main Aug 1, 2026
5 of 6 checks passed
@idanlodzki
idanlodzki deleted the ci/build-and-typecheck branch August 1, 2026 19:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

25-25: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Include both lockfiles in the npm cache key.

The repository has separate root and opsimate-docs lockfiles. setup-node uses the dependency file in the repository root by default. Changes to opsimate-docs/package-lock.json will not invalidate this cache. cache-dependency-path supports multiple dependency files. (github.com)

♻️ Proposed fix
           node-version: '24'
           cache: 'npm'
+          cache-dependency-path: |
+            package-lock.json
+            opsimate-docs/package-lock.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml at line 25, Update the setup-node npm cache
configuration near the cache setting to define cache-dependency-path with both
the root package-lock.json and opsimate-docs/package-lock.json, so changes to
either lockfile invalidate the cache.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 16-17: Update the checkout step using actions/checkout@v7 to set
persist-credentials to false, and add an explicit top-level permissions
declaration granting only the required access for this pull_request workflow,
preserving later steps unless they require authenticated Git operations.

In `@opsimate-docs/package.json`:
- Line 49: Regenerate opsimate-docs/package-lock.json from the updated
engines.node constraint in package.json so its root metadata records >=20.0
instead of >=18.0. Use the package manager from the opsimate-docs project and
commit the resulting lockfile metadata without unrelated dependency changes.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Line 25: Update the setup-node npm cache configuration near the cache setting
to define cache-dependency-path with both the root package-lock.json and
opsimate-docs/package-lock.json, so changes to either lockfile invalidate the
cache.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 87391f58-fb70-4840-be30-b3218c381aeb

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdd435 and 6174a63.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • .github/workflows/link-check.yml
  • opsimate-docs/package.json

Comment thread .github/workflows/ci.yml
Comment on lines +16 to +17
- name: Checkout repository
uses: actions/checkout@v7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

grep -q 'persist-credentials: false' .github/workflows/ci.yml
grep -q 'contents: read' .github/workflows/ci.yml

Repository: OpsiMate/documentation

Length of output: 160


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- ci.yml excerpt ---'
sed -n '1,180p' .github/workflows/ci.yml

printf '\n%s\n' '--- action checkout occurrences ---'
rg -n "actions/checkout|persist-credentials|permissions:|contents:|npm ci|npm run" .github/workflows/ci.yml || true

printf '\n%s\n' '--- package scripts and lifecycle hooks ---'
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
if p.exists():
    data=json.loads(p.read_text())
    print(json.dumps(data.get('scripts', {}), indent=2))
else:
    print('package.json not found')
PY

Repository: OpsiMate/documentation

Length of output: 1246


🌐 Web query:

actions/checkout README persist-credentials true false default token checkout token configured as git credential

💡 Result:

The persist-credentials input for the actions/checkout GitHub Action controls whether the repository's authentication token or SSH key is configured in the local git configuration [1][2]. When persist-credentials is set to true (which is the default value) [1][3][2], the action configures the provided authentication token or SSH key into the local git environment [1][2]. This allows subsequent steps in your workflow to run authenticated git commands (e.g., git push or git pull) without needing to manually re-authenticate [1][4][2]. Key technical points regarding this behavior include: - Security Mechanism: The action automatically removes the configured credentials during the post-job cleanup step [1][4][2]. - Implementation: In more recent versions of the action, credentials are stored in a separate file within the runner's temporary directory rather than directly in the.git/config file, which improves security [1]. - Opt-out: You can disable this behavior by explicitly setting persist-credentials: false in your workflow step [1][4]. Doing so prevents the action from configuring git with the token, which is often recommended if you do not need to perform authenticated git operations in subsequent steps, as it limits the exposure of the token within the job [5][6]. While there has been community discussion and proposals to change the default value to false to enhance security, as of August 2026, the default remains true [7][6].

Citations:


🌐 Web query:

github actions /README.md contents read pull request token permissions

💡 Result:

To read a file like README.md from your repository within a GitHub Actions workflow, the GITHUB_TOKEN requires read access to the contents scope [1][2][3]. For standard workflows, you can explicitly set this in your workflow YAML file using the permissions key [1][4]: permissions: contents: read Key Considerations: 1. Permission Inheritance: If you define a permissions key in your workflow, any permissions you do not explicitly list are set to none [1]. Therefore, if your workflow needs to perform other tasks (such as checking out code or making API calls), ensure those scopes are also included [1][5]. 2. Default Behavior: If no permissions are specified in the workflow, the token inherits the default settings configured at the repository or organization level [1][2][6]. Many organizations configure these defaults to be read-only for security [1][6]. 3. Pull Requests from Forks: For security reasons, GitHub automatically restricts the GITHUB_TOKEN to read-only access for pull requests originating from public forks, regardless of your workflow or repository-level permission settings [1][7][5]. If your workflow must perform write operations triggered by a fork, you typically need to use the pull_request_target event instead, which runs with elevated trust using the base repository's context [7][5]. However, use caution with this event to avoid exposing repository secrets to potentially untrusted code [7]. To verify your current token permissions during a workflow run, you can use the GitHub CLI (gh) within a step: - run: gh auth status - run: gh api /repos/{owner}/{repo}/actions/permissions For reading repository files, standard actions like actions/checkout generally handle authentication automatically, provided the workflow has the necessary contents: read permission [7][2].

Citations:


🌐 Web query:

github actions malicious repository contents read token fetch code npm ci

💡 Result:

Running code from untrusted repositories within GitHub Actions workflows poses a critical security risk, often leading to Remote Code Execution (RCE) on the runner and subsequent theft of secrets, such as the GITHUB_TOKEN or other configured API credentials [1][2][3]. Common Attack Patterns: - Pwn Requests: Workflows using the pull_request_target trigger can accidentally execute untrusted code from forked repositories with the permissions of the base repository [4][5]. If such a workflow checks out the PR head branch and runs commands like npm install or build scripts, it executes attacker-controlled code [4]. - Compromised Actions: Malicious actors may compromise third-party GitHub Actions (e.g., via tag hijacking) to inject malicious payloads into your workflow, which are then executed with the runner's full privileges [3]. - Dependency Exploitation: Commands like npm install or npm ci execute lifecycle scripts (e.g., preinstall, postinstall) found in project dependencies [6][7]. If a malicious dependency is present, these scripts execute arbitrary code during the CI/CD process [6][7]. Security Risks of npm ci/install: - Lifecycle Scripts: npm automatically runs scripts defined in package.json during installation [7]. These scripts provide an easy vector for RCE if a compromised package is included [6][7]. - Lockfile Manipulation: Attackers can inject malicious dependencies by modifying the package-lock.json file in a pull request [8]. While npm ci is safer than npm install in CI environments because it enforces the lockfile, it still installs whatever the lockfile specifies, meaning it will install a malicious package if the lockfile has been poisoned [8]. Hardening Recommendations: - Minimize Permissions: Explicitly define permissions for every workflow using a top-level permissions block (e.g., permissions: {}) and grant only the absolute minimum required access [9][10]. - Disable Lifecycle Scripts: Use npm ci --ignore-scripts to prevent the execution of malicious install-time scripts [6][7]. - Secure Triggers: Be extremely cautious with pull_request_target. Use it only when necessary and ensure workflows do not check out or execute code from untrusted PRs directly [4][5]. Consider splitting workflows into two: one that runs untrusted code in a low-trust context and another that only processes validated output [4]. - Use Egress Filtering: Implement tools (e.g., Harden-Runner) to restrict the network traffic of your workflows, preventing the exfiltration of stolen tokens to external servers [10][4]. - Pin Dependencies and Actions: Always pin third-party actions to a specific, immutable commit SHA rather than a branch or tag [8]. - Use Trusted Publishers: Replace long-lived credentials (like npm tokens) with OIDC-based short-lived tokens (Trusted Publishing) to reduce the impact of a potential credential theft [11][6].

Citations:


🌐 Web query:

actions/checkout v8 README persist-credentials v7 persist-credentials

💡 Result:

As of August 1, 2026, there is no official version 8 of the actions/checkout GitHub Action [1]. The current major version is v7 [1][2]. Regarding the persist-credentials input: Functionality: This input determines whether the authentication token (or SSH key) used to clone the repository is configured in the local git configuration [3][4][2]. When enabled (the default), it allows subsequent steps in your workflow to execute authenticated git commands (such as git push or git fetch) without needing to re-authenticate [3][5][2]. Security Context: The default value for persist-credentials is true [4][2]. Because the token is stored in the git configuration, any subsequent step in the same job can theoretically access this credential [6][7]. To enhance security and prevent accidental exposure or unauthorized use of the token by later steps, it is a common best practice to explicitly set persist-credentials: false if your workflow does not require running authenticated git commands after the checkout is complete [6][7]. Changes in behavior: While the functional purpose of persist-credentials remains consistent, there have been improvements in how these credentials are stored. For example, in v6, the action was updated to store credentials in a file under $RUNNER_TEMP rather than directly in the repository's .git/config file to improve security [8][9]. If you are seeing references to "v8" in your specific context, it may be an error or a misunderstanding, as official releases have only reached v7 [1]. Always refer to the official GitHub repository for the most accurate and up-to-date documentation regarding inputs and their defaults [10][2].

Citations:


Disable persisted checkout credentials for this PR build.

This PR workflow runs checkout on pull_request, then runs npm ci and package scripts. actions/checkout@v7 keeps the GitHub token configured for later Git commands unless persist-credentials: false is set. Add an explicit top-level permission, and disable persisting the checkout token unless the later steps need authenticated Git access.

🔒 Proposed fix
 on:
   push:
     branches: [main]
   pull_request:
     branches: [main]
   workflow_dispatch:
 
+permissions:
+  contents: read
+
 jobs:
@@
       - name: Checkout repository
         uses: actions/checkout@v7
+        with:
+          persist-credentials: false
🧰 Tools
🪛 zizmor (1.28.0)

[warning] 16-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 16 - 17, Update the checkout step
using actions/checkout@v7 to set persist-credentials to false, and add an
explicit top-level permissions declaration granting only the required access for
this pull_request workflow, preserving later steps unless they require
authenticated Git operations.

Source: Linters/SAST tools

},
"engines": {
"node": ">=18.0"
"node": ">=20.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json

with open("opsimate-docs/package.json") as file:
    manifest = json.load(file)

with open("opsimate-docs/package-lock.json") as file:
    lockfile = json.load(file)

expected = manifest["engines"]["node"]
actual = lockfile["packages"][""]["engines"]["node"]

assert actual == expected, f"lockfile has {actual!r}; manifest has {expected!r}"
PY

Repository: OpsiMate/documentation

Length of output: 295


Regenerate the docs lockfile for the new engine constraint.

opsimate-docs/package-lock.json still records engines.node as >=18.0, while opsimate-docs/package.json declares >=20.0. Regenerate the lockfile from opsimate-docs and commit the matching metadata so install workflows do not reuse stale lockfile metadata.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@opsimate-docs/package.json` at line 49, Regenerate
opsimate-docs/package-lock.json from the updated engines.node constraint in
package.json so its root metadata records >=20.0 instead of >=18.0. Use the
package manager from the opsimate-docs project and commit the resulting lockfile
metadata without unrelated dependency changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant