A GitHub Action, written in TypeScript, that associates a project with the Conviso GraphQL API. It triggers a sync to Conviso Platform for a project held by an external scanner (Fortify, Checkmarx, Dependency Track, and any other integration Conviso supports), and can record the repository and branch the scan came from.
- Features
- Quick start
- Inputs
- Outputs
- Usage
- Prerequisites
- Project structure
- Development
- Publishing
- Contributing
- License
- Custom inputs: accepts
api-key,project-id,integrationandcompany-id, plus the optionalrepository-urlandbranch. - Branch awareness: associates the scan with a specific repository and branch, so findings land on the branch they came from — resolved from the workflow's own context, so the common case needs no extra YAML.
- GraphQL integration: executes a mutation against the Conviso GraphQL API to associate a project from Checkmarx, Dependency Track, Fortify, or any other integration Conviso has.
- Outputs: exposes the associated Asset's id and name to later steps.
- Secret masking: registers the API key with the runner, so it is replaced by
***in the logs even when a workflow passes it literally. - Unit testing: Vitest suite covering the request payload, the context resolution and the wiring between them.
- TypeScript, bundled with esbuild into a single committed
dist/index.js.
name: Sync to Conviso
on:
push:
branches: [main]
jobs:
conviso-sync:
runs-on: ubuntu-latest
steps:
- uses: convisoappsec/github-sync-task@v1
with:
api-key: ${{ secrets.CONVISO_API_KEY }}
integration: 'CONVISO_SCANNER'
company-id: '99'
project-id: '1a-2b-3c'That is the whole integration. repository-url and branch default to the repository and branch
the workflow is running for, so the scan is associated with the right branch without any further
configuration.
Keep the API key in a repository or organization secret, as above. Anything passed under
with:is visible to anyone who can read the workflow file, and a key written literally there would also be readable in the run's YAML. This action callscore.setSecreton whatever it receives, so the value is masked in the log either way — but that does not un-publish a key committed to the repository.
| Input | Required | Default | Description |
|---|---|---|---|
api-key |
yes | — | API key used to authenticate requests to the Conviso GraphQL endpoint. Pass it from a secret. |
integration |
yes | — | Name of the integration in Conviso's GraphQL schema (e.g. CONVISO_SCANNER, DEPENDENCY_TRACK, FORTIFY, CHECKMARX). |
company-id |
yes | — | Company ID in Conviso Platform. |
project-id |
no | — | Project ID from the external scanner. |
repository-url |
no | $GITHUB_SERVER_URL/$GITHUB_REPOSITORY |
Repository this scan belongs to. When set, the Asset in Conviso Platform becomes a repository and branch is recorded as one of its branches. |
branch |
no | the branch that triggered the run | Branch this scan covers. Only takes effect together with repository-url. |
| Output | Description |
|---|---|
asset-id |
ID of the Asset associated in Conviso Platform. Empty when the API returned none. |
asset-name |
Name of the Asset associated in Conviso Platform. Empty when the API returned none. |
repository-url and branch are optional, and both default to the workflow's own context:
| Input | Resolved from |
|---|---|
repository-url |
GITHUB_SERVER_URL + GITHUB_REPOSITORY — e.g. https://github.com/org/repo |
branch |
GITHUB_BASE_REF when present, otherwise GITHUB_REF with refs/heads/ stripped |
Passing them explicitly overrides the detection:
- uses: convisoappsec/github-sync-task@v1
with:
api-key: ${{ secrets.CONVISO_API_KEY }}
integration: 'CONVISO_SCANNER'
company-id: '99'
project-id: '1a-2b-3c'
repository-url: 'https://github.com/org/repo' # Optional, defaults to this repository
branch: 'main' # Optional, defaults to this run's branchThree things to know before turning this on:
branchonly takes effect together withrepository-url. Sent on its own, Conviso Platform ignores it. The action emits a warning when it detects that combination, but the run still succeeds.- The Asset gets renamed. Once associated with a repository, the Asset in Conviso Platform is
named after the repository (
org/repo) rather than the project name reported by the scanner. - Branch association also depends on the feature being enabled for your company in Conviso Platform. Until then the action behaves exactly as it would without the two inputs, and sending them is harmless.
On pull_request and pull_request_target events, GITHUB_REF is the temporary merge ref
(refs/pull/42/merge) and GITHUB_REF_NAME is the literal 42/merge — neither is a branch name.
The action uses GITHUB_BASE_REF there, which carries the branch the pull request is merging
into. No configuration is needed:
on:
pull_request:
jobs:
conviso-sync:
runs-on: ubuntu-latest
steps:
- uses: convisoappsec/github-sync-task@v1
with:
api-key: ${{ secrets.CONVISO_API_KEY }}
integration: 'CONVISO_SCANNER'
company-id: '99'If you would rather record the branch the pull request came from, pass it explicitly:
branch: ${{ github.head_ref }}.
- id: conviso
uses: convisoappsec/github-sync-task@v1
with:
api-key: ${{ secrets.CONVISO_API_KEY }}
integration: 'DEPENDENCY_TRACK'
company-id: '99'
project-id: '1a-2b-3c'
- run: echo "Associated asset ${{ steps.conviso.outputs.asset-name }} (#${{ steps.conviso.outputs.asset-id }})"- Node.js: version 24.x or later, for local development. Download Node.js
- Yarn: version 4.x, provided by Corepack (
corepack enable) — the version is pinned inpackage.jsonunderpackageManager. - A GitHub repository with Actions enabled.
- GraphQL API access: credentials for the Conviso GraphQL API at
https://app.convisoappsec.com/graphql.
github-sync-task/
├─ .github/
│ └─ workflows/
│ ├─ ci.yml # Typecheck, test, and verify dist/ is in sync
│ └─ release.yml # Moves the v<major> tag on every published release
├─ src/
│ ├─ associateProject.ts # Core logic for GraphQL API interaction
│ ├─ workflowContext.ts # Resolves repository/branch from the workflow environment
│ ├─ main.ts # The action itself: inputs, fallbacks, outputs
│ ├─ index.ts # Entry point named by action.yml
│ └─ tests/
│ ├─ associateProject.test.ts # Unit tests for the request payload
│ ├─ workflowContext.test.ts # Unit tests for the context resolution
│ ├─ main.test.ts # Unit tests for the wiring
│ └─ e2e.ts # End-to-end run against Conviso Platform
├─ dist/
│ ├─ index.js # Bundled action — committed, this is what runs
│ └─ index.js.LEGAL.txt # Licence notices of the bundled dependencies
├─ action.yml # Action metadata: inputs, outputs, branding, runtime
├─ tsconfig.json # TypeScript configuration
├─ vitest.config.mts # Test configuration
├─ package.json # Project dependencies and scripts
├─ yarn.lock # Yarn lockfile
└─ README.md # Project documentation
git clone https://github.com/convisoappsec/github-sync-task.git
cd github-sync-task
corepack enable
yarn installyarn buildThis bundles src/index.ts and every runtime dependency into a single dist/index.js with
esbuild, and writes the dependencies' licence notices to dist/index.js.LEGAL.txt.
dist/ is committed on purpose. A JavaScript action runs straight from the repository — the
runner checks the repo out and executes runs.main, and never installs dependencies. A dist/
that lags behind src/ means every consumer keeps running the old behaviour, which is why CI
rebuilds the bundle and fails when it differs from the committed one. Always run yarn build
before committing a change under src/.
yarn test # one-shot run
yarn test:watch # re-run on change
yarn test:coverage # with a coverage report
yarn typecheck # tsc --noEmit
yarn all # typecheck + test + build, what CI doesTests run on Vitest rather than Jest — @actions/core 3.x is published as
ESM only, which Jest can only load through a fair amount of configuration.
yarn test-e2e runs the bundled action exactly the way the runner does — node dist/index.js
with the inputs handed over as INPUT_* environment variables — against the real Conviso
Platform. Credentials come from your environment, so nothing of yours ends up committed:
yarn build
CONVISO_API_KEY=<key> CONVISO_COMPANY_ID=<id> CONVISO_PROJECT_ID=<id> \
CONVISO_INTEGRATION=DEPENDENCY_TRACK yarn test-e2eCONVISO_REPOSITORY_URL and CONVISO_BRANCH are optional; leaving them out exercises the
fallback to the workflow variables. The step's outputs are printed at the end.
To exercise the action inside a real workflow before releasing it, reference the checkout itself:
- uses: actions/checkout@v7
- uses: ./ # the action in this repository, at this commit
with:
api-key: ${{ secrets.CONVISO_API_KEY }}
integration: 'DEPENDENCY_TRACK'
company-id: '99'A GitHub Action needs no packaging step: consumers reference the repository at a git ref
(convisoappsec/github-sync-task@v1). Publishing to the Marketplace is about
discoverability — a release tag is what actually makes a version usable.
-
Rebuild the bundle and run the checks.
yarn all
-
Raise the version in
package.json, and add an entry toCHANGELOG.md. Nothing in the runtime readspackage.json, but keeping it aligned with the tag is what makes it possible to tell which release adist/index.jscame from. -
Commit
dist/along with the source change. CI fails the pull request otherwise. -
Tag and release. Create a GitHub release from a
vMAJOR.MINOR.PATCHtag (e.g.v1.2.0). Therelease.ymlworkflow then moves thev1tag to that release, so everyone pinned to@v1picks it up.
Recommend to consumers that they pin either the major tag (@v1, gets fixes automatically) or a
full commit SHA (@a1b2c3…, immutable — the strictest supply-chain option). A branch reference
such as @master is the one to avoid.
The full walkthrough, including the one-time account setup, the exact release form and how to update or remove a listing, is in docs/publishing-marketplace.md. The short version:
- The repository must be public, own a single
action.ymlin its root, and have a README. - The
nameinaction.ymlmust be unique across the Marketplace, andbrandingmust be set — both are already the case here. - Enable two-factor authentication on the account or organization that owns the repository.
- On the repository home page, use the "Publish this Action to the GitHub Marketplace" banner and accept the GitHub Marketplace Developer Agreement.
- Draft a release, tick "Publish this Action to the GitHub Marketplace", choose the primary
and secondary categories, tag it
vX.Y.Z, and publish.
Every later release repeats step 5 only.
Contributions are welcome! To contribute:
-
Fork the repository
-
Create a feature branch
git checkout -b feature/your-feature-name
-
Commit your changes — including a rebuilt
dist/yarn all git commit -m "Add some feature" -
Push to the branch
git push origin feature/your-feature-name
-
Open a pull request
Ensure your code adheres to the project's coding standards and includes relevant tests.
This project is licensed under the MIT License.
