Prerequisites
- A Katilyst API key. An Account Admin generates one from the Admin Portal. Keys are shown once when generated, and a lost key cannot be recovered.
- Permission to add workflow files and repository secrets in the repositories you are instrumenting.
- A way to resolve GitHub users to email addresses. This is the part that needs thought — see below.
Resolve identity first
Katilyst identifies a User by email address. GitHub webhook payloads carry a username, and the email field is frequently empty because users can keep it private. Settle this before writing any workflow, because every other part is straightforward and this one is not. Three approaches, in the order most organizations land on them.Derive the email from the username
Derive the email from the username
If your GitHub accounts are provisioned through SSO, usernames usually match the local part of a work email, so
jsmith becomes jsmith@example.com.This is the simplest approach and it works well in GitHub Enterprise Cloud with SAML. It fails for anyone whose GitHub account predates the SSO rollout, and for contractors on personal accounts.Keep a mapping file
Keep a mapping file
Store a small JSON or CSV file in the repository mapping GitHub usernames to email addresses, and look up the author in the workflow.This handles the exceptions the derivation approach misses, and it has the advantage of being reviewable. It needs maintaining as people join and leave, which is work somebody has to own.
Query your identity provider
Query your identity provider
If you run SCIM provisioning, your identity provider holds the authoritative mapping and can be queried at run time.The most robust option and the most work. Worth it when you are instrumenting many repositories and the mapping would otherwise drift.
Decide your three mappings
As with any integration, three choices determine how this is built.
The third deserves the most thought. The author wrote the fix, the merger approved it, and a reviewer may have been the one who caught the issue. Your program decides which of those behaviours it wants more of.
Configure the action in Katilyst
1
Create an Available Action
In Katilyst, create an Instance action named something recognizable, such as GitHub — Security Fix Merged. Set the Attribute it changes, the amount, and any frequency limit.
2
Find your project ID
Call List projects and note the
id of the program you are integrating with.3
Find your action ID
Call List a project’s available actions and note the
id of the action you created.Store the API key as a secret
In the repository, go to Settings → Secrets and variables → Actions → New repository secret. Name itKATILYST_API_KEY and paste the key as the value.
Store the key at the organization level instead if you are instrumenting several repositories, so there is one place to rotate it.
GitHub encrypts secrets and masks them in run logs, so the key never appears in output. This is a real advantage over integrations that store credentials in a rule configuration where anyone with edit access can read them.
Add the workflow
Create.github/workflows/katilyst.yml in the repository.
.github/workflows/katilyst.yml
Why it is written this way
Two details are worth keeping if you adapt this. Untrusted values go throughenv, never directly into the shell. A pull request title is attacker-controlled text, and interpolating ${{ github.event.pull_request.title }} straight into a run: block lets anyone who can open a pull request execute commands on your runner. Passing it as an environment variable and referencing ${PR_TITLE} closes that. This is GitHub’s own guidance on script injection and it applies to any workflow that touches pull request content.
jq builds the JSON rather than string interpolation. A title containing a quote or a backslash would produce malformed JSON and a confusing 400. jq escapes correctly and is preinstalled on GitHub-hosted runners.
permissions: {} grants the job no access to the repository, which is all it needs since it never checks out code.
Adapting it
For several repositories, move the body of this workflow into a reusable workflow or a composite action and call it from each one, so there is a single place to update when the action ID or the identity rule changes.
Verify
Open a pull request, apply your security label, and merge it.- Open the Actions tab in the repository and find the run. A successful step prints nothing, since
curl --silentstays quiet on success and--failmakes a non-2xx response fail the step. - Call List a user’s logged actions and confirm the award landed.
status field on the result. APPROVED means the reward applied.
Troubleshooting
- The workflow never runs. The
ifcondition did not match. Comment it out temporarily, merge a test pull request, and confirm the job fires at all before narrowing again. An unmatched condition produces no run and no error, which makes it easy to misread as a broken workflow. - The workflow succeeds and no reward appears. Read the action back and check its
status.PENDINGmeans the Available Action requires admin approval and is waiting for it, which is program configuration rather than a workflow fault. ALIMIT_EXCEEDED_TIMEFRAMErecord came from someone submitting inside the platform rather than from this workflow — frequency limits do not apply to API calls. curlexits 22.--failreturning this means Katilyst rejected the request outright. Add--includetemporarily to see the response body and status code in the run log. A409here means the User is not eligible for that action, which is a program rule rather than an integration fault.- A
400response. Usually the derived email does not match a User in that Katilyst Project. Call List a project’s users and compare against what the workflow built. - A
401response. The key is invalid, the secret is missing or misnamed, or theAPI-Keyprefix was dropped from the header value. An invalid key is the most common cause — confirm it has not been rotated or revoked since the secret was stored. - The run log shows an empty email.
PR_AUTHORresolved to nothing, which usually means the event payload differs from what the workflow expects. Print the value to the log before the curl call to see what arrived.
Related
Core concepts
Instance versus State actions, guardrails, and how rewards are decided.
Log an action
Full reference for the endpoint this workflow calls.
