@constal/github
v2.2.0
Published
`@constal/github` provides GitHub Tools, a webhook Channel, and an AuthProvider using the public Constal SDK. GitHub API requests use a bound Service Resource; signing keys and API tokens are supplied through Credentials.
Readme
GitHub integration for Constal
@constal/github provides GitHub Tools, a webhook Channel, and an AuthProvider using the public Constal SDK. GitHub API requests use a bound Service Resource; signing keys and API tokens are supplied through Credentials.
The package separates three ordinary platform concepts:
GitHub Tool code (this repository, bundled into the Agent)
│ ctx.invoke
▼
provider-neutral Service Resource
│ scoped authorization Credential
▼
GitHub APIThe exported Tools implement GitHub-specific argument validation, response projection, repository archive handling, and reconciliation for comments, reactions, branches, and pull requests. The bound Service Resource performs only generic authenticated HTTP transport. Credential Providers remain independent packages and feed the normal Credential and scoped-binding lifecycle.
PR observation Tools expose current PR state and mergeability, paginated PR/review lists, checks, and commit status. github_pull_request_update updates an existing PR. repository.branch.publish accepts an observed expectedHead when updating an existing branch: the new commit retains that head as its parent and the update never forces over concurrent commits. A race or failed update remains an error, not a fabricated successful receipt.
repository.branch.publish reads its workspace archive from the bound CAS Resource with getRaw. Sandbox command output references already belong to that CAS; they do not need a Driver-artifact import. An unavailable or denied CAS read stops publication before any Git blobs or branches are created.
Use from an Agent
Import the Tools needed by the Agent:
import { agent } from "@constal/sdk";
import { GITHUB_TOOLS } from "@constal/github";
export default agent({
id: "repository-agent",
version: "1.0.0",
model: "model",
tools: GITHUB_TOOLS,
async onMessage(message, ctx) {
const turn = await ctx.turn({ system: "Work with the selected repository.", objective: message,
tools: Object.keys(GITHUB_TOOLS) });
return turn.message.content;
},
});Declare the provider Tool Resource in constal.agent.json so the managed builder resolves and bundles the exact immutable package source:
{
"toolPackages": [
"crn:constal:production:platform:default:tool/github"
],
"bindings": {
"github": "crn:constal:production:platform:default:service/github",
"cas": "crn:constal:production:platform:default:cas/constal"
}
}GITHUB_SERVICE_CONFIG and GITHUB_SERVICE_EGRESS describe the provider-neutral Service Resource required by the Tools. Register those definitions through the public Resource API and bind the resulting Service to your Agent.
Webhook Channel
channels/github/ receives authenticated GitHub deliveries and routes them to subscribed tenant Channels. channels/github-auth/ verifies the signature before decoding installation, repository, and sender identities. Both are ordinary managed packages deployed through POST /v1/deployments. For each archive, copy its manifest to the archive root in place of constal.tool.json, keeping the channels/ and src/ directories in their existing layout. Each deployment archive must have exactly one root resource manifest.
Create a signing Credential, then register a Service using GITHUB_WEBHOOK_VERIFIER_CONFIG, with that Credential bound to webhook-secret and GITHUB_WEBHOOK_VERIFIER_EGRESS. The Service performs generic HMAC verification without network access. Install it as the local github-webhook-verifier Resource required by the AuthProvider manifest.
The source Channel target is:
{ "resourceKind": "channel", "subscriptions": { "provider": "github" } }Configure credentialProviders with the exact { "crn": "…", "hash": "…" } identities of trusted installation Credential Providers. A source Channel starts with no trusted issuers. Its authorizeSubscription handler accepts only current provider evidence for the requested installation and repository.
Subscribers use the public Channel installation API. Each ingressRoutes entry supplies its source and the Credential references that may prove access:
{
"provider": "github",
"key": "installation:123:repository:owner:repo",
"credentials": [{ "crn": "…", "hash": "…" }]
}Use githubWebhookSource(installationId, "owner/repo") to generate this key. Install one route per selected repository. Multiple Channels, including Channels in different tenants, can subscribe to the same source; each supplies its own authorized Credential references. Installation-wide events without a repository are acknowledged without fanout.
The host checks Credential access and obtains fresh evidence before changing Channels, bindings, or subscriptions. It stores the authorized references independently of subscriber code, then verifies current access again before writing to a tenant inbox and before invoking tenant authentication. Revoking one tenant's Credential leaves other subscribers connected. Delivery and retries are independent for each inbox.
A subscriber's AuthProvider uses authorizeGitHubWebhook with the expected sourceChannel CRN in its configuration. It consumes host-authenticated provenance for the exact repository and maps the verified sender to a principal. The source signing key and signature stay at the source boundary. For a directly addressed webhook, bind a tenant-owned verifier and github Service so the helper can verify the signature and repository access.
GitHub App installation and user OAuth lifecycles are provided by the separate credential-provider-github-app and credential-provider-github-oauth packages. The shared App variant proves the installing user's writable repository access before minting automation tokens. This package contains no operator credentials, private service URLs, or platform provisioning scripts.
Repository packages
Private repository archives are acquired through the ordinary repository.archive Service operation. Configure a shared Service with GITHUB_SERVICE_CONFIG, GITHUB_SERVICE_EGRESS, and this principal-scoped Credential binding:
{
"authorization": {
"kind": "scoped",
"key": "github-user",
"owner": "principal",
"required": true
}
}The Console uses that Service for connected GitHub imports. The public deployment API accepts an artifact source:
{
"source": {
"resource": { "crn": "…", "hash": "…" },
"operation": "repository.archive",
"arguments": { "owner": "owner", "repository": "repo", "ref": "main" }
}
}Acquisition uses normal Resource policy checks and Credential injection. The resulting immutable artifact is verified against its tenant namespace before deployment. A pending acquisition is resumed with the same idempotency key. Credentials never enter deployment requests or package archives. Repository packages support archives up to 10 MiB; ordinary GitHub API responses retain their 4 MiB limit.
