Repository scanning
Repository scanning is the capability that finds
componecat.yaml descriptors in your repositories and
turns them into catalog entities. It runs two ways that complement each other: a
scheduled scan crawls your organizations looking for descriptors the catalog
doesn’t know about yet, and a webhook re-ingests a descriptor the moment
someone pushes a change to it.
Both are configured on a Git integration — see Integrations for connecting one. GitHub, GitLab, and Bitbucket all support repository scanning.
What the credential needs
Section titled “What the credential needs”The connection’s credential is what reads your repositories, so it needs:
- GitHub — read access to repository contents and code search across the organizations you want scanned. A personal access token or a GitHub App installation both work.
- GitLab — the
read_apiscope (orapi). A project access token covers a single project; use a personal access token to scan groups. - Bitbucket — an access token with read access to the workspaces and repositories you want scanned.
Private repositories that the credential can’t see are invisible to the scan.
Enable and configure scanning
Section titled “Enable and configure scanning”On the integration’s page, open the Git Scanning card. Set the configuration first, then switch the capability on — the panel is editable while the capability is off, so the first run uses your settings.
| Setting | Meaning |
|---|---|
| Schedule (cron) | How often the scan runs. Default 0 */6 * * * — every six hours. |
| Target Orgs/Groups | Which organizations, groups, or workspaces to crawl. A comma-separated list, or * for everything the credential can see. |
| File Pattern | Which files count as descriptors. Default componecat.yaml. |
Use Run now on the card to trigger a scan immediately — handy right after you change the pattern or targets.
What a scheduled scan does
Section titled “What a scheduled scan does”For each target, the scan asks the provider’s search API for repositories containing the descriptor filename, then lists each candidate repository’s files and matches them against your full pattern. Every match that the catalog doesn’t already track is queued for ingestion.
That last part is the important one: a scheduled scan ingests descriptors that are new to the catalog. Edits to a descriptor that already has an entity arrive through the webhook, or when someone selects Refresh on the entity’s Repository tab, which re-reads its descriptor on the spot.
File patterns
Section titled “File patterns”The pattern is matched against each repository’s file listing with a small glob
syntax: * matches within one path segment, ? matches a single character, and
** matches any number of segments.
| Repository layout | File Pattern | Result |
|---|---|---|
| Descriptors anywhere in the repo | (leave as the default) | componecat.yaml matched at any depth. |
| One descriptor per top-level service directory | services/*/componecat.yaml |
Matches services/api/componecat.yaml and siblings; a descriptor at the repo root or nested deeper is not discovered. |
| Services nested arbitrarily deep under one root | services/**/componecat.yaml |
Matches at any depth under services/. |
| A different descriptor filename | **/catalog-info.yaml |
Any depth, different filename. |
A bare filename with no / matches at any depth. A pattern containing / is
anchored to that directory structure.
Note that the pattern applies to scans only. Webhook ingestion always looks
for files named componecat.yaml, at any depth, whatever pattern you set here —
so a custom descriptor filename is discovered by scans but not by pushes.
Connect the webhook
Section titled “Connect the webhook”The webhook is what makes the catalog update within seconds of a merge. Setting it up takes two values from Componecat and one webhook in your Git provider.
- Open the integration. The Webhook card at the top of its capabilities shows the endpoint URL to use, with a button to copy it. The URL ends in your integration’s id, so each connection has its own.
- In the same card, choose Rotate Webhook Secret and confirm. The new secret is shown once, so copy it before closing the dialog.
- Create the webhook in your Git provider with that URL and secret, as below. On GitLab you can use a signing token instead of the secret.
Rotating the secret invalidates the previous one immediately, so update the provider’s webhook configuration right away or pushes will be rejected.
GitHub
Section titled “GitHub”Add a webhook on the repository or organization:
- Payload URL — the endpoint from the integration page.
- Content type —
application/json. - Secret — the rotated secret.
- Events — Pushes, and Pull requests if you use catalog intake.
GitLab
Section titled “GitLab”Add a webhook under the project’s or group’s Webhooks settings:
- URL — the endpoint from the integration page.
- Trigger — Push events, and Merge request events if you use catalog intake.
- Request authentication — a signing token (recommended) or a secret token, as below.
On GitLab 19.0 and later, use a signing token. GitLab signs every delivery with it and includes a timestamp, so Componecat can check that the push really came from your GitLab, wasn’t changed on the way, and isn’t an old delivery being replayed. GitLab generates the token and shows it only once:
- Under Configure request authentication, choose Generate signing token
and copy the token. It starts with
whsec_. - In Componecat, open the integration’s Webhook card, choose Set Signing Token, paste the token, and save. The card then shows the signing token as Set. The token is stored encrypted and is never shown again; to change it, generate a new one in GitLab and choose Replace Signing Token.
On older GitLab versions, use a secret token instead: paste the rotated secret into Secret token. GitLab sends it with every delivery.
To move an existing webhook from a secret token to a signing token without missing a push, configure both for a while. Generate the signing token in GitLab and set it in Componecat while the secret token stays in place: signed deliveries are then checked against the signing token, and anything unsigned against the secret. Once deliveries succeed, remove the secret token from the GitLab webhook.
When a delivery is signed and the integration has a signing token, the signature alone decides: a delivery with a wrong or outdated signature is rejected even if it also carries the right secret token. Remove on the Webhook card deletes the stored signing token, after which deliveries are checked against the secret again.
Bitbucket
Section titled “Bitbucket”Add a repository webhook:
- URL — the endpoint from the integration page.
- Secret — the rotated secret.
- Triggers — Repository: Push, and if you use catalog intake, Pull Request: Created, Updated, Merged and Declined.
Bitbucket’s push events don’t list the files that changed, so a push re-reads the descriptor at the repository root. Descriptors in subdirectories of a Bitbucket repository are discovered by scheduled scans instead.
What a push does
Section titled “What a push does”Only pushes to the repository’s default branch are processed; anything else
is acknowledged and ignored, except a push to a branch a catalog intake opened,
which shows that someone else committed to its merge request. Pull request and
merge request events are read only for
catalog intake, and other events
are acknowledged and ignored. Componecat looks at the
files the push touched, picks out every componecat.yaml among them (at any
depth), and queues one ingestion per descriptor — so a monorepo push that changes
three descriptors updates three entities independently. Deleting a descriptor is
a change too, and is processed the same way.
If the integration also backs your organization’s wiki, the same webhook keeps the wiki up to date: a push to the wiki’s branch that changes its Markdown files starts a wiki sync. See Sync on push.
Reading scan history
Section titled “Reading scan history”The Git Scanning card lists recent runs while the capability is enabled, with a status, timestamps, a discovered count — descriptors newly queued for ingestion in that run — and any errors. Errors are per repository: a repository the credential can’t read, or one whose file listing failed, is recorded and the scan carries on with the rest.
Runs in progress refresh automatically, so a Run now shows its result without a reload.
A scan only queues descriptors for ingestion, so a discovered descriptor can still fail. The ingestion log shows how each one ended.
Reading the ingestion log
Section titled “Reading the ingestion log”The Ingestion Log on the Git Scanning card records every attempt to ingest a descriptor, whichever way it started: a push, a scan, or a Refresh. A file with several entities gets a row for each. Each row shows the repository and file, the entity when it could be identified, what started the attempt, the commit, and a status:
| Status | Meaning |
|---|---|
| Succeeded | The descriptor was applied to the catalog. |
| Warnings | The descriptor was applied, with problems listed on the row, such as a relationship target that doesn’t exist yet. |
| Failed | The descriptor wasn’t applied. The row says why. |
| Removed | The file was deleted, or no longer declares the entity. Its entities are marked missing. |
A descriptor that fails before any entity exists has nowhere else to report, so this is the place to look when an entity you expected never appears. The log refreshes on its own, and keeps entries for 30 days. Pushes Componecat ignores, such as one to a non-default branch, never reach ingestion and aren’t listed; your Git provider’s webhook log has those.
Repository metadata on entities
Section titled “Repository metadata on entities”Connecting a Git provider also enriches entities that link to a repository, even ones you created by hand. Componecat fetches the repository’s languages, README, default branch, and description, and tracks whether the repository is reachable, archived, or gone. Values you set manually aren’t overwritten. Without a matching integration this only works for public repositories — the integration’s credential is what makes private repositories readable.
When the integration has Git Scanning turned on, the same refresh also syncs the
entity’s descriptor: the one it’s already synced from, or a componecat.yaml at
the repository root. It runs when an entity is linked to a repository and when
you select Refresh on its Repository tab. Entities managed by another
integration, or released from their source, are left alone.
Troubleshooting
Section titled “Troubleshooting”- Pushes aren’t ingested. Check the delivery response in your Git provider’s
webhook log.
401means the signature didn’t match — usually a secret that was rotated on one side only.404means the URL is wrong, or the integration doesn’t have Git Scanning enabled. - Deliveries get
429. Componecat accepts up to 60 webhook deliveries a minute from each sending address, and pushes share that limit with pull request and merge request events, which an organization-level webhook sends many of. A refused push of a newcomponecat.yamlis found by the next scheduled scan. A refused push that changed a descriptor already in the catalog isn’t, because scans skip those: redeliver it from your Git provider’s webhook log, or select Refresh on the entity’s Repository tab. A refused pull request or merge request event needs nothing, because Componecat checks each open merge request itself as a backstop. - GitLab deliveries get
401with a signing token. Make sure the token set in Componecat is the one currently on the GitLab webhook: generating a new signing token in GitLab replaces the old one, so set the new one in Componecat too. A webhook that has only a signing token needs it set in Componecat, or every delivery fails. A signed delivery is also rejected if its timestamp is more than five minutes away from Componecat’s clock, so on a self-managed GitLab, check that the server’s clock is right. - The push was accepted but nothing changed. The response body says why: a
push to a non-default branch and a push that touched no
componecat.yamlare both acknowledged and ignored. - A scan finds nothing. Confirm the target organizations are spelled as the provider knows them, that the credential can see those repositories, and that the file pattern matches where your descriptors actually live.
- An existing descriptor’s changes never appear. Scheduled scans skip descriptors already tracked by the catalog; that path is the webhook’s job. Until the webhook is connected, Refresh on the entity’s Repository tab re-reads it.
- A very large push. Webhook payloads above 512 KB are rejected. The scheduled scan still picks up anything new from such a push.
- A scan keeps discovering the same descriptor. It’s failing to ingest, so the catalog still treats it as new. The ingestion log says why — see also When a descriptor fails to ingest.
- A descriptor was found but the entity is wrong. That’s ingestion, not discovery — see Catalog as code for how descriptor and manual edits are reconciled.
Related
Section titled “Related”- Catalog as code — how descriptors become entities.
- Descriptor file reference — every field.
- Integrations — connecting the provider.
- Documentation sync — pulling Markdown from the same repositories.