Skip to main content

In this article

Build Workflows

HVE Core uses GitHub Actions for continuous integration, quality validation, security scanning, and release automation. The workflow architecture emphasizes reusable components and parallel execution for fast feedback.

Pipeline Overview

Workflow Inventory

WorkflowTriggerPurpose
pr-validation.ymlPull request, manualPre-merge quality gate for main, develop, and both release branches
release-prerelease-prepare.ymlMerged PR to main, manualOpen the reviewed main to release/prerelease promotion PR
release-prerelease.ymlMerged PR to release/prereleasePrepare metadata or create the exact odd-minor tag and draft
release-stable.ymlPublished PreRelease, manualOpen the reviewed release/prerelease to release/stable promotion PR
release-stable-publish.ymlMerged PR to release/stablePrepare metadata or create the exact even-minor tag and draft
release-vsix-publish.ymlPush of v* or prerelease-v*Produce and publish the exact immutable channel release
weekly-security-maintenance.ymlSunday 2 AM UTC, manualScheduled security posture review
weekly-validation.ymlSchedule, manualWeekly full validation sweep
security-scan.ymlPush to main/developCodeQL security validation
release-marketplace-stable.ymlPublished Stable release, manualVS Code extension Marketplace publishing
release-marketplace-prerelease.ymlPublished PreRelease, manualVS Code extension pre-release publishing
copilot-setup-steps.ymlManualCoding agent environment setup
devcontainer-change-log.ymlPush to main/developLogs devcontainer infrastructure file changes to the step summary
devcontainer-lockfile-check.ymlReusableValidates devcontainer lockfile integrity and SHA-256 pinning
scorecard.ymlSchedule, push, post-tag releaseOpenSSF Scorecard security analysis
codeql-analysis.ymlScheduleWeekly CodeQL security scan (also reusable)
dependency-review.ymlPull requestDependency vulnerability review (also reusable)
sha-staleness-check.ymlManualSHA reference freshness check (also reusable)
deploy-docs.ymlPush to main, manualDocusaurus documentation site deployment
create-stale-docs-issues.ymlScheduleAutomated stale docs issue creation from ms.date freshness
msdate-freshness-check.ymlSchedule, manualms.date freshness validation across documentation
label-sync.ymlPush to main, manualRepository label synchronization
workflow-permissions-scan.ymlSchedule, manualGitHub Actions permissions audit
weekly-gh-code-scanning.ymlMonday 3 AM UTC, manualWeekly GitHub code scanning alert retrieval and issue creation
vex-detect.ymlSchedule, release, manualDependency vulnerability scan and VEX triage issue creation

GitHub Agentic Workflow markdown files (issue-triage.md, issue-implement.md, pr-review.md, dependency-pr-review.md, doc-update-check.md, and vex-draft.md) compile to *.lock.yml workflows and are documented in Agentic Workflows.

Reusable Workflows

Individual validation workflows called by orchestration workflows:

WorkflowPurposenpm Script
markdown-lint.ymlMarkdownlint validationnpm run lint:md
spell-check.ymlcspell dictionary checknpm run spell-check
frontmatter-validation.ymlAI artifact frontmatter schemasnpm run lint:frontmatter
markdown-link-check.ymlBroken link detectionnpm run lint:md-links
link-lang-check.ymlLink language validationnpm run lint:links
yaml-lint.ymlYAML syntax validationnpm run lint:yaml
ps-script-analyzer.ymlPowerShell static analysisnpm run lint:ps
table-format.ymlMarkdown table formattingnpm run format:tables
pester-tests.ymlPowerShell unit testsnpm run test:ps
skill-validation.ymlSkill structure validationnpm run validate:skills
dependency-pinning-scan.ymlDependency pinning validationN/A (PowerShell direct)
sha-staleness-check.ymlSHA reference freshness*N/A (PowerShell direct)
codeql-analysis.ymlCodeQL security scanning*N/A (GitHub native)
dependency-review.ymlDependency vulnerability review*N/A (GitHub native)
gh-code-scanning.ymlGitHub code scanning alert retrievalN/A (PowerShell direct)
create-gh-code-scanning-issues.ymlCreate GitHub code scanning issues from alertsN/A (bash + gh CLI direct)
extension-provenance-signer.ymlSplit VSIX packaging, attestation, and uploadN/A
copyright-headers.ymlCopyright header validationnpm run validate:copyright
gitleaks-scan.ymlSecret detection scanningN/A (gitleaks direct)
plugin-validation.ymlPlugin manifest, locator, and hook validationnpm run plugin:validate
extension-marketplace-publish.ymlExtension marketplace publishingN/A
python-lint.ymlPython lint and format checks (ruff)npm run lint:py
pytest-tests.ymlPython unit testsnpm run test:py
pip-audit.ymlPython dependency auditingN/A (pip-audit direct)
fuzz-tests.ymlPython fuzz testingN/A (pytest direct)
docusaurus-tests.ymlDocusaurus test suiteN/A (npm test)
model-validation.ymlModel reference validationnpm run lint:models
ai-artifact-validation.ymlAI artifact structure validationnpm run lint:ai-artifacts
devcontainer-lockfile-check.ymlDevcontainer lockfile integritynpm run validate:devcontainer-lockfile
action-version-consistency-scan.ymlAction version consistencynpm run lint:version-consistency

Workflows marked with * are dual-purpose: they accept workflow_call for reuse by orchestration workflows and also run independently via their own triggers.

Composite Actions

Composite actions package reusable step sequences that workflows invoke directly. Unlike reusable workflows (called via uses: at the job level with workflow_call), composite actions are referenced as steps within a job.

ActionPurposeReference
setup-ps-modulesCached PowerShell module install with retryuses: ./.github/actions/setup-ps-modules

The setup-ps-modules action caches modules keyed on scripts/security/ps-module-versions.json and retries installation with exponential backoff on PSGallery failures. Workflows that need PowerShell modules must use uses: ./.github/actions/setup-ps-modules instead of inline Install-Module steps, consistent with the convention recorded in .github/copilot-instructions.md.

PR Validation Pipeline

The pr-validation.yml workflow serves as the primary quality gate for all pull requests. It runs parallel linting, security, and testing jobs.

Jobs

JobReusable WorkflowValidates
spell-checkspell-check.ymlSpelling across all files
markdown-lintmarkdown-lint.ymlMarkdown formatting rules
table-formattable-format.ymlMarkdown table structure
psscriptanalyzerps-script-analyzer.ymlPowerShell code quality
yaml-lintyaml-lint.ymlYAML syntax
pester-testspester-tests.ymlPowerShell unit tests
frontmatter-validationfrontmatter-validation.ymlAI artifact metadata
skill-validationskill-validation.ymlSkill directory structure
link-lang-checklink-lang-check.ymlLink accessibility
markdown-link-checkmarkdown-link-check.ymlBroken links
dependency-pinning-checkdependency-pinning-scan.ymlDependency pinning
devcontainer-lockfile-checkdevcontainer-lockfile-check.ymlDevcontainer lockfile integrity
npm-auditInlinenpm dependency vulnerabilities
codeqlcodeql-analysis.ymlCode security patterns
copyright-headerscopyright-headers.ymlCopyright header compliance
plugin-validationplugin-validation.ymlPlugin manifest, locator, hooks
gitleaks-scangitleaks-scan.ymlSecret detection

All jobs run in parallel with no dependencies, enabling fast feedback (typically under 3 minutes).

Release Promotion and Publication

The preparation workflows each contain exactly two jobs:

WorkflowJobsSource and target
release-prerelease-prepare.ymlprepare-promotion, open-promotion-prmain to release/prerelease
release-stable.ymlprepare-promotion, open-promotion-prrelease/prerelease to release/stable

Each preparation starts from the target branch, merges the current source, restores target-owned release metadata, writes the exact release-as, and opens a reviewed PR. Promotion heads are stable per hop and are updated without force. The promotion merge creates no tag.

The PR-close release workflows accept only the exact promotion or managed head for their channel. A promotion merge selects PR-only mode. A managed PR merge selects tag-only mode, and release-please creates prerelease-v<version> for PreRelease or v<version> for Stable plus the matching draft at that managed merge commit.

Release Version Allocation

Ordinary version allocation is branch-owned. PreRelease reads the current release/prerelease version and returns the same major, minor plus two, and patch zero. Stable reads the promoted PreRelease version and returns the promoted major, promoted minor plus one, and patch zero. Current Stable state only rejects a candidate that does not advance it. The ordinary sequence is 3.3.101 to 3.5.0 to 3.6.0.

No commit classification or automatic patch, minor, or major release class participates in ordinary allocation. The plugin manifest and VSIX use the same channel version. A major-line transition, or a Stable patch or hotfix, requires a separate explicit manifest and release-state decision. Odd/even minor parity is repository policy aligned with VS Code Marketplace guidance and behavior, not a requirement of MAJOR.MINOR.PATCH syntax.

Release Channel Jobs

release-prerelease.yml and release-stable-publish.yml each contain only validate-trigger, release-please, and sync-release-pr. They remain reviewed, pre-tag workflows. They validate the promotion or managed head, synchronize committed release state, and let release-please create the exact immutable tag and draft.

The resulting tag push starts release-vsix-publish.yml, the sole post-tag producer for both channels. It validates the protected exact tag, source commit, channel, expected release branch, and synchronized committed state. It performs bounded exact-draft discovery through 12 attempts separated by 10 seconds. A matching draft proceeds through dependency SBOM generation, packaging and attestation, provenance verification, publication, and milestone closure. Stable additionally retains OpenVEX attestation, verification notes, and a best-effort dependency diff when a previous dependency SBOM is available.

extension-provenance-signer.yml provides the signer path and separates duties. Its package job installs dependencies and packages the extension with only contents: read. Its dependent privileged attest job receives the fixed-name VSIX and dependency SBOM through digest-checked transfers. It does not install dependencies or package the extension. No job both packages and signs.

Verification is cryptographic first, then semantic and fail closed. GitHub CLI verification authenticates the exact subject digest, signer workflow and revision, source ref and revision, and hosted-runner constraint. Policy then requires the exact subject and digest, SLSA provenance v1, GitHub Actions workflow/v1, the push event, a GitHub-hosted runner, the expected external parameters, one resolved source dependency, and the expected builder identity.

If the producer sees a matching published release, it verifies the exact asset set and provenance without rebuilding. Recovery depends on the observed state. A tag-only state first requires release-please to complete the exact draft; a draft-only state first requires release-please to materialize the tag. Once the tag and release both exist, rerun the original immutable tag-push workflow. Partial draft assets can be replaced before publication, but every required job and provenance check must pass before the one-way publish operation. The producer has no default workflow_dispatch path. Never move, delete, or recreate a release tag, create a replacement release identity, or convert a published release back to draft. The finite discovery window fails closed on uncertain state and does not guarantee draft visibility.

Both channels publish their draft with a release GitHub App token. The resulting published event triggers a separate Marketplace workflow, which consumes only the VSIX from that published GitHub release and does not rebuild. Main is not part of either release completion graph. It remains a ref-less development-tip channel sourced from canonical .github content and is not updated by release completion. Release branches, immutable tags, and published releases own release state and history.

Tag governance is a mandatory activation prerequisite, but it is not yet active or proven. The intended release-tags-creation-by-release-app ruleset restricts creation only and grants a bypass to the Release App. The separate release-tags-immutable ruleset restricts updates, deletion, and force pushes with no bypass. Documentation of these controls is not evidence that they are installed.

This architecture does not establish SLSA Build Level 3. Future Stable and PreRelease releases still need successful runtime evidence, active governance evidence, platform assurance mapping, and qualified human review before making that claim.

The ref-less microsoft/hve-core registration sources canonical content from .github through the main catalog. An explicit marketplace refresh and plugin update are required for that catalog, which has no release gate, SBOM, or attestation. PreRelease and Stable retain reviewed, release-gated, SBOM-covered, and attested immutable delivery through moving branch registrations and exact tags.

Security Workflows

Weekly Security Maintenance

The weekly-security-maintenance.yml workflow runs every Sunday at 2AM UTC, providing scheduled security posture review.

JobPurpose
validate-pinningVerify dependency pinning compliance
check-stalenessDetect outdated SHA references
codeql-analysisFull CodeQL security scan
summaryAggregate security status report

Security Validation Tools

ToolScriptChecks
Dependency PinningTest-DependencyPinning.ps1Actions use SHA refs; npm uses exact versions
SHA StalenessTest-SHAStaleness.ps1SHAs reference recent commits
audit-ciaudit-ci --config audit-ci.jsonKnown vulnerabilities in dependencies, using the allowlist in audit-ci.json
CodeQLGitHub nativeCode patterns indicating security issues
GitleaksgitleaksSecret detection in repository history
Dependency ReviewGitHub nativeDependency vulnerability analysis

Extension Publishing

Both Marketplace entry workflows publish release assets selected by a validated exact channel tag.

Channel Tags and Attestation Signers

ChannelExact release tagAttestation signer
PreReleaseprerelease-v<version>extension-provenance-signer.yml
Stablev<version>extension-provenance-signer.yml

Both callers pass the exact tag to the generic publisher, which resolves the signer to the one constant both channels sign from. It downloads the matching VSIX release asset, verifies the attestation, and then publishes through Azure OIDC and vsce.

Marketplace Build

Both channel workflows validate the one-entry catalog and call the generic publisher for hve-core. The publisher validates inputs, downloads hve-core-<version>.vsix, verifies its lane-specific attestation, prepares the locked publisher toolchain from protected main, and publishes through Azure OIDC and vsce.

Stable and PreRelease package the same root plugin.json membership into the same extension identity. Each selected branch or exact-tag snapshot carries its own root manifest, README, and LICENSE. The channel controls version, release source, and the VS Code Marketplace pre-release flag, not component inclusion.

Version Channels

ChannelVersion PatternMarketplace
StableEven minor (1.2.0)Main listing
Pre-releaseOdd minor (1.3.0)Pre-release flag

Hosted Marketplace selection and installed-client switching remain operator observations, not results of local workflow or documentation validation.

npm Script Mapping

Workflows invoke validation through npm scripts defined in package.json:

npm ScriptCommandUsed By
lint:mdmarkdownlint-cli2markdown-lint.yml
lint:md:fixmarkdownlint-cli2 --fixLocal
spell-checkcspellspell-check.yml
spell-check:fixcspell --show-suggestionsLocal
lint:frontmatterValidate-MarkdownFrontmatter.ps1frontmatter-validation.yml
lint:md-linksMarkdown-Link-Check.ps1markdown-link-check.yml
lint:linksInvoke-LinkLanguageCheck.ps1link-lang-check.yml
lint:yamlInvoke-YamlLint.ps1yaml-lint.yml
lint:psInvoke-PSScriptAnalyzer.ps1ps-script-analyzer.yml
lint:plugin-manifestSync-PluginManifest.ps1 -Checkplugin-validation.yml
lint:version-consistencyTest-ActionVersionConsistency.ps1Local
validate:localLocal-safe repository validation aggregateLocal-safe default
validate:docsDocusaurus lint, label registry, typecheck, and component testsLocal-safe docs default
ci:docs:test:e2eDelegates to the Docusaurus Playwright E2E suiteCI-owned browser lane
ci:docs:setup:e2eProvisions Chrome for the Docusaurus browser laneCI-owned browser setup
format:tablesmarkdown-table-formattertable-format.yml
test:psInvoke-PesterTests.ps1pester-tests.yml
validate:skillsValidate-SkillStructure.ps1skill-validation.yml
validate:copyrightTest-CopyrightHeaders.ps1copyright-headers.yml
extension:preparepwsh ./scripts/extension/Prepare-Extension.ps1 && npm run extension:postprocessLocal
extension:prepare:prereleasepwsh ./scripts/extension/Prepare-Extension.ps1 -Channel PreRelease && npm run extension:postprocessLocal
extension:postprocessmarkdownlint-cli2 + markdown-table-formatter (extension/**/*.md)Local
extension:packagePackage-Extension.ps1Local
extension:package:prereleasePackage-Extension.ps1 -PreReleaseLocal
plugin:syncSync-PluginManifest.ps1Local manifest update
plugin:validatePlugin manifest check plus hook validationplugin-validation.yml
lint:pyruff check + ruff format --checkpython-lint.yml
lint:modelsValidate-ModelReferences.ps1model-validation.yml
lint:ai-artifactsValidate-PlannerArtifacts.ps1 -FailOnMissingai-artifact-validation.yml
lint:permissionsTest-WorkflowPermissions.ps1workflow-permissions-scan.yml
lint:ps-module-pinsTest-PSModulePins.ps1Local
lint:dependency-pinningTest-DependencyPinning.ps1dependency-pinning-scan.yml
audit:npmaudit-ci --config audit-ci.jsonpr-validation.yml
test:pyuv run pytestpytest-tests.yml
ci:eval:lint:vallyBuild-AgentBehaviorSpec.ps1 -WhatIf && vally lint --eval-spec evals/CI-owned static lane
ci:eval:lint:schemaTest-EvalSpec.ps1CI-owned static lane
ci:eval:lint:textTest-EvalSpecText.ps1CI-owned static lane
ci:eval:lint:safetyTest-VallyTestSafety.ps1CI-owned static lane
ci:eval:lint:skillsvally lint .github/skills/CI-owned static lane
ci:eval:runRuns all eval suitesCI-owned model-backed lane
ci:eval:run:skillsvally eval --suite skill-qualityCI-owned model-backed lane
ci:eval:run:agentsvally eval --suite agent-behaviorCI-owned model-backed lane
ci:eval:run:scriptsvally eval --suite script-validationCI-owned model-backed lane
ci:eval:equivalenceInvoke-BaselineEquivalence.ps1CI-owned model-backed comparison lane
ci:eval:presenceTest-StimulusPresence.ps1 (changed-artifact eval-spec coverage gate)CI-owned manifest lane
ci:eval:executeInvoke-VallyEvals.ps1 (run evals for changed artifacts)CI-owned model-backed lane
ci:eval:moderateInvoke-ContentModeration.ps1CI-owned moderation lane
ci:eval:moderate:corpusInvoke-CorpusModeration.ps1CI-owned moderation lane
ci:eval:moderate:artifactsInvoke-ArtifactModeration.ps1CI-owned moderation lane
ci:eval:moderate:testRuns Invoke-ContentModeration.Tests.ps1CI-owned test lane
ci:eval:dashboardNew-EquivalenceDashboard.ps1CI-owned noninteractive report lane
ci:eval:behavior-promptsvally eval --eval-spec evals/behavior-conformance/prompts.eval.yamlCI-owned model-backed lane
ci:eval:behavior-instructionsvally eval --eval-spec evals/behavior-conformance/instructions.eval.yamlCI-owned model-backed lane
ci:eval:behavior-skillsvally eval --eval-spec evals/behavior-conformance/skill-behavior.eval.yamlCI-owned model-backed lane
ci:eval:agentInvoke-AgentMatrix.ps1 (agent behavior matrix)CI-owned model-backed lane
ci:eval:agent:matrixInvoke-AgentMatrix.ps1 -All -Tier nightlyCI-owned model-backed lane
ci:eval:agent:matrix:dryrunInvoke-AgentMatrix.ps1 -All -Tier nightly -WhatIfCI-owned dry-run lane
ci:eval:agent:changedInvoke-AgentMatrix.ps1 for changed agents (PR tier)CI-owned model-backed lane
ci:eval:agent:dashboardNew-AgentMatrixDashboard.ps1CI-owned noninteractive report lane
ci:eval:agent:dashboard:openNew-AgentMatrixDashboard.ps1 -OpenCI-owned interactive lane
ci:eval:agent:reportRuns ci:eval:agent:matrix then ci:eval:agent:dashboardCI-owned noninteractive report lane
ci:eval:agent:report:dryrunRuns ci:eval:agent:matrix:dryrun then ci:eval:agent:dashboardCI-owned noninteractive dry-run report lane

Python Lint Parity

npm run lint:py runs the same command set as python-lint.yml: ruff check followed by the non-mutating ruff format --check. Execution conditions still differ in three ways:

  • Provisioning: the hosted lane runs uv sync --locked itself. The local lint runner intentionally verifies rather than provisions, while test:py provisions before testing. A locked project without the exact ruff version fails before ruff executes and reports uv sync --locked as the setup action. Devcontainer and coding-agent setup synchronize every lint-eligible project, including the telemetry hook, with uv sync --locked.
  • Project scope: local discovery covers directories containing a pyproject.toml except generated plugins/ output, dependency trees, and scripts/evals/moderation. The moderation eval remains excluded from per-PR Python matrix jobs and local lint because its torch/detoxify environment belongs to the dedicated moderation lane. Other eligible projects outside .github/skills, including .github/hooks/shared/telemetry, remain in local and hosted lint scope.
  • Execution gate: the hosted lane defaults to running only when a pull request changes .py or .pyi files, while the local lane always scans every discovered project.

🤖 Crafted with precision by ✨Copilot following brilliant human instruction, then carefully refined by our team of discerning human reviewers.