# Artifact Hub Chart Release and Security-Report Drift Watch (`kingii98/artifact-hub-chart-release-and-security-report-drift-watch`) Actor

Watches a list of Artifact Hub packages and reports each new chart version, application-version change, and change in the Artifact Hub security report summary, against a stored baseline. Each change record also gives the signature and deprecation state. P

- **URL**: https://apify.com/kingii98/artifact-hub-chart-release-and-security-report-drift-watch.md
- **Developed by:** [kingii98](https://apify.com/kingii98) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 package baselineds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Artifact Hub Chart Release and Security-Report Drift Watch

Know when a Helm chart that you pin ships a new version, changes its
application version, or gets a worse Artifact Hub security report. Each change
record also gives you the signature and the deprecation state of the chart.

You pin chart versions. Artifact Hub knows the current version of each chart,
the application version inside it, the signature and deprecation state, and the
counts of the security report by severity. This Actor polls that public API for
the packages that you watch, compares each answer with a stored baseline, and
writes one row for each change.

The Actor needs no cluster access, no kubeconfig, no Helm binary, no chart
download, and no browser. It reads one public JSON API.

### What the Actor does

1. It reads the Artifact Hub package record of each watched package.
2. It compares the answer with the baseline of that package from the last run.
3. It writes one dataset record for each detected change, one record for each
   watched package, and one summary record.
4. It writes the new state back to a named key-value store.

The first run of a package writes the baseline and reports no change. From the
second run on, you get only what moved. Run the Actor on a daily Apify
schedule: chart publishers release on their own cadence, and Artifact Hub
re-scans a chart after its release, so the watch must be standing.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `packages` | array | three demo charts | 1 to 150 packages, each as `repository/package`. A full Artifact Hub package URL works too, and `kind:repository/package` names another package kind for one entry. |
| `kind` | string | `helm` | The Artifact Hub package kind of an entry that does not name one. |
| `major_changes_only` | boolean | `false` | Report a package only when the new version crosses a major version. |
| `state_name` | string | `DEFAULT` | The name of the baseline set. Use one name for each watch list. |
| `request_timeout_seconds` | integer | `30` | Timeout for each Artifact Hub request. |
| `concurrency` | integer | `4` | The largest number of packages polled at the same time. |
| `max_run_seconds` | integer | `240` | Wall-clock deadline for the watch list. |

Every field has a default, so a run with an empty input works and watches the
three demo charts:

```json
{
  "packages": [
    "prometheus-community/kube-prometheus-stack",
    "ingress-nginx/ingress-nginx",
    "grafana/grafana"
  ]
}
```

The Actor needs no API key and no secret. It speaks to one host,
`artifacthub.io`, and it builds every URL itself, so no input can point it at a
private or reserved address.

An entry that is not a usable package reference does not stop the run: it gets
the `INVALID_PACKAGE` reason code, it is not polled, and it is not charged.

### Output

#### One record for each detected change

A change record is written when the version, the application version or the
security report summary moved. A package where only the signature or the
deprecation state moved keeps that fact in its package record, with the field
`suppressed_reason`, and gets no change record.

| Field | Description |
| --- | --- |
| `package` | The watched package, as `kind/repository/package`. |
| `previous_version`, `new_version` | The chart version before and after. |
| `previous_app_version`, `new_app_version` | The application version inside the chart, before and after. |
| `released_at` | The release date of the new version, in UTC. |
| `signed`, `previous_signed`, `signatures` | The signature state, and the signature kinds that Artifact Hub knows. |
| `deprecated`, `previous_deprecated` | The deprecation state. |
| `security_critical` … `security_unknown` | The counts of the Artifact Hub security report summary, by severity. |
| `security_delta_critical` … `security_delta_unknown` | The change in each count since the baseline. A negative number means fewer findings. |
| `security_total`, `security_total_delta` | The counts added up, and their change. |
| `change_types` | Which fields moved: `version`, `app_version`, `security_report`, `signature`, `deprecation`. |
| `major_change` | The new version crosses a major version. |
| `package_url`, `repository_url` | The Artifact Hub page, and the chart repository. |

#### One record for each watched package

The package record holds the reason code, the state of the baseline
(`created`, `compared` or `unavailable`), the current version, the current
security counts, and, when a change was found but not reported, the field
`suppressed_reason`.

#### One summary record

The summary record holds the packages polled, the baselines written, the
changes detected, the major changes, the new critical and high findings, the
deprecated and unsigned packages, and the packages whose poll failed.

#### Reason codes

| Code | Meaning |
| --- | --- |
| `OK` | Artifact Hub answered and the record was read. |
| `PACKAGE_NOT_FOUND` | Artifact Hub does not know this repository and package. |
| `SOURCE_HTTP_ERROR` | Artifact Hub answered with another status. |
| `SOURCE_BAD_JSON` | The answer is not a usable package record. |
| `SOURCE_TOO_LARGE` | The answer is above the byte cap of the Actor. |
| `TIMEOUT`, `CONNECT_FAIL` | The request did not finish. |
| `RUN_DEADLINE` | The run reached `max_run_seconds` before this package. |
| `INVALID_PACKAGE` | The input entry is not a usable package reference. |

A failed poll, an unknown package and a run with no change are results, not
faults. The run succeeds, the dataset holds the rows, and the status message
says what happened. A run fails only when the Actor itself malfunctions.

### State

The Actor keeps one record for each package in the named key-value store
`artifact-hub-chart-baseline`. The record holds the version, the application
version, the release date, the signature and deprecation state, and the
security counts of the last run. Without this baseline there is no change and
no charge.

The record is not written when the run could not read the package, and not
written when the charge limit of the run stops the report, so the next run
still reports that change.

To start a watch again from zero, use another `state_name`.

### Pricing: pay per event

| Event | When it is charged | Count |
| --- | --- | --- |
| `package-baselined` | The first run of a package writes its baseline. No change is reported. | One for each package baselined |
| `release-or-security-change-detected` | A later run finds a new version, a new application version, or a changed security report summary. | One for each changed package |

A package that did not change is not charged. A package where only the
signature or the deprecation state moved is not charged either: that move is
not in the billing unit, so the run keeps it in the package record, writes the
new baseline, and makes no change record. A poll that failed, a package that
Artifact Hub does not know and a rejected input entry are not charged either. When `major_changes_only` is on, a change that does not cross a major
version is neither reported nor charged.

A watch list of 50 charts therefore costs 50 baseline events on the first run,
and after that only the charts that actually moved.

### Limits

- 150 packages for each run, the contract limit of the watch list.
- One request for each package, with one retry for an answer that a retry can
  change.
- Redirects are not followed, and each answer is read up to 8 MB.
- The whole poll stops at `max_run_seconds`.

### Development

```bash
uv sync
uv run pytest
uv run ruff check .
```

# Actor input Schema

## `packages` (type: `array`):

1 to 150 Artifact Hub packages, each written as "repository/package", for example "prometheus-community/kube-prometheus-stack". A full Artifact Hub package URL works too. To watch a package of another kind, write "kind:repository/package", for example "olm:community-operators/prometheus". If you leave this field empty, the Actor watches the three public demo charts shown below.

## `kind` (type: `string`):

The Artifact Hub package kind of an entry that does not name one. Helm charts are the default. An entry can name another kind with the "kind:repository/package" form.

## `major_changes_only` (type: `boolean`):

When this is on, the Actor reports a package only when the new chart version crosses a major version, for example 74.x to 75.x. A patch release, a minor release and a security-report change alone are then not reported and not charged, and the baseline still moves forward. A version that is not semantic counts as a major change, so the watch never drops a change that it cannot read.

## `state_name` (type: `string`):

The name of the baseline set inside the named key-value store "artifact-hub-chart-baseline". Use one name for each watch list. The first run of a package writes the baseline and reports no change.

## `request_timeout_seconds` (type: `integer`):

Timeout for each Artifact Hub request. A package gets one request and, when the answer can change, one retry.

## `concurrency` (type: `integer`):

The largest number of packages polled at the same time. Artifact Hub is a public free API, so a small number is polite and fast enough for 150 packages.

## `max_run_seconds` (type: `integer`):

Wall-clock deadline for the watch list. A package that the run does not reach before this deadline gets the RUN\_DEADLINE reason code and keeps its baseline, so the next run polls it. The run still succeeds.

## Actor input object example

```json
{
  "packages": [
    "prometheus-community/kube-prometheus-stack",
    "ingress-nginx/ingress-nginx",
    "grafana/grafana"
  ],
  "kind": "helm",
  "major_changes_only": false,
  "state_name": "DEFAULT",
  "request_timeout_seconds": 30,
  "concurrency": 4,
  "max_run_seconds": 240
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "packages": [
        "prometheus-community/kube-prometheus-stack",
        "ingress-nginx/ingress-nginx",
        "grafana/grafana"
    ],
    "kind": "helm",
    "major_changes_only": false,
    "state_name": "DEFAULT",
    "request_timeout_seconds": 30,
    "concurrency": 4,
    "max_run_seconds": 240
};

// Run the Actor and wait for it to finish
const run = await client.actor("kingii98/artifact-hub-chart-release-and-security-report-drift-watch").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "packages": [
        "prometheus-community/kube-prometheus-stack",
        "ingress-nginx/ingress-nginx",
        "grafana/grafana",
    ],
    "kind": "helm",
    "major_changes_only": False,
    "state_name": "DEFAULT",
    "request_timeout_seconds": 30,
    "concurrency": 4,
    "max_run_seconds": 240,
}

# Run the Actor and wait for it to finish
run = client.actor("kingii98/artifact-hub-chart-release-and-security-report-drift-watch").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "packages": [
    "prometheus-community/kube-prometheus-stack",
    "ingress-nginx/ingress-nginx",
    "grafana/grafana"
  ],
  "kind": "helm",
  "major_changes_only": false,
  "state_name": "DEFAULT",
  "request_timeout_seconds": 30,
  "concurrency": 4,
  "max_run_seconds": 240
}' |
apify call kingii98/artifact-hub-chart-release-and-security-report-drift-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kingii98/artifact-hub-chart-release-and-security-report-drift-watch"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/xUSGD2DPPozSkqhA4/builds/LhNhUweyyJd4BHYuO/openapi.json
