Skip to content

Releases: paramify/paramify-fetchers

v0.5.1-beta

v0.5.1-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 02 Sep 20:38
3ad7f05

Fixed

  • An AWS failure now says why, not just which call broke. 0.5.0-beta got
    all 80 AWS fetchers reporting through $FETCHER_STATUS_FILE, but 250 of their
    CLI calls ran as aws ... 2>/dev/null and the matching log line recorded only
    a label. Of 310 failure records, 8 carried the AWS error text and 302 carried
    none
    — so expired credentials, a missing IAM permission and throttling all
    arrived looking identical, while being three unrelated fixes. All 80 also
    passed a hardcoded partial_failure, so metadata.error_code carried no
    information for the largest category in the repo.

    Both are fixed. metadata.error now carries the AWS error text behind the
    calls that failed, and metadata.error_code is derived from it:

    {
      "error": "2 AWS API failure(s); first: aws sts get-caller-identity failed; aws ec2 describe-security-groups (list) failed (exit=254) -- aws: [ERROR]: An error occurred (InvalidClientTokenId) ... The security token included in the request is invalid. | aws: [ERROR]: An error occurred (AuthFailure) ... AWS was not able to validate the provided access credentials",
      "code": "auth_failed"
    }

    That code is what the not-enabled classification work and the
    deleted-mid-scan decision were both waiting on.

    No call site was rewritten. aws in
    fetchers/aws/_shared/aws.sh is now a shell
    function shadowing the CLI, so all 250 calls keep their exact text — including
    2>/dev/null — and still have their stderr captured. stdout, stderr and the
    exit code reach the caller unchanged, so the 2>"$_ERR" + grep pattern the
    not-enabled check depends on still works, synchronously. The one constraint
    this adds: a fetcher must reach the CLI as plain aws, never command aws or
    an absolute path, or its calls go unclassified. A test enforces that.

    Classification is regex over botocore's wording, which is the only signal a
    CLI-based fetcher has — the SDK-based categories read a typed exception
    instead. A future AWS rewording can therefore downgrade a code to
    partial_failure; that is the safe direction, and
    tests/test_aws_failure_classification.py pins the current wordings verbatim.

  • A not-enabled service still exits 0. The wrapper captures the
    SubscriptionRequiredException stderr like any other, so this was the
    regression risk worth naming: had it been recorded as a failure, every account
    without Macie, Inspector, or Shield would have started reporting a spurious
    partial_failure. aws_service_unavailable is still checked first and
    short-circuits, verified end-to-end and pinned by a test.

  • Failure reasons read correctly again. The separator was built with
    tr '\n' '; ', and tr maps one character to one character — so it emitted
    ; with no space and left a trailing one before the (+N more) suffix.

Changed

  • Two Azure SDK pins widened, and CI can now tell whether that is safe.
    azure-mgmt-network moves from <32 to <33 and
    azure-mgmt-recoveryservicesbackup from <11 to <12, in both
    pyproject.toml and requirements.txt. Anyone installing .[azure] gets the
    new majors.

    The reason this is worth an entry: CI installed .[dev] and .[dev,tui] but
    never .[azure], so no test in the suite had ever imported an Azure SDK.

    Every azure-mgmt major that has broken this category broke it silently —
    wrong or empty evidence rather than an exception — which meant a dependency PR
    widening an Azure pin went green on evidence that proved nothing about Azure.
    One did
    exactly that: it relaxed the load-bearing azure-mgmt-monitor<7 and passed all
    twelve checks, while 7.0.0 removes the diagnostic_settings operation group
    that three fetchers read.

    A new azure-sdk (surface) job is now the only one that installs the Azure
    extra, and it pins the surface in the shapes a major bump actually takes it
    away: relocated client imports, vanished operation groups, vanished methods,
    and the model-field renames that produce wrong rather than empty evidence — 56
    checks across all 27 Azure fetchers. It asserts the extra really resolved
    before running, because the module opens with pytest.importorskip and a
    failed install would otherwise skip and report green. azure-mgmt-monitor
    majors are held back until the operation group returns; a test fails when it
    does, so the pin and the hold get lifted together instead of going stale.

  • The container base image moves to Python 3.14 (deploy/Dockerfile:
    python:3.12-slim → python:3.14-slim), and CI now tests on 3.14 as well
    as 3.10–3.13. The interpreter the Dockerfile and the dev environments actually
    run was previously the one nothing gated.

  • Corrected the 0.5.0-beta entry below. It said metadata.error "now carries
    the actual cause", and illustrated it with a report rich in AWS error text.
    That example came from one of the 8 call sites that captured stderr, out of
    310 — it was not representative, and for AWS the accurate claim at 0.5.0-beta
    was that the report names the call that failed. The entry now says so, and
    this release is what makes the original claim true.


Full changelog: v0.5.0-beta...v0.5.1-beta

Install by checking out the tag — a plain clone tracks moving main:

git clone https://github.com/paramify/paramify-fetchers.git
cd paramify-fetchers && git checkout v0.5.1-beta
python -m venv .venv && source .venv/bin/activate
pip install -e '.[all]'      # or `pip install -e .` for the headless CLI only

Azure and GCP need their own extras (.[azure], .[gcp]) — see the README.

v0.5.0-beta

v0.5.0-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 02 Sep 16:42
2c0e454

Added

  • CrowdStrike Falcon fetcher set — seven fetchers and a fourteenth
    category, contributed by @StewartClaw:
    managed host inventory, Spotlight vulnerabilities, detections, prevention
    policies, Zero Trust Assessment, FileVantage file integrity, and host firewall
    policies and rules. All seven share one OAuth2 client
    (_shared/falcon_client.py)
    that handles token refresh, cursor and offset pagination, and the
    Retry-After contract on 429s. Commercial and GovCloud both supported —
    cloud_region selects a commercial region or us-gov-1 / us-gov-2, and the
    client follows the region-discovery redirect Falcon's auth endpoint issues
    when the host is wrong.

    Built without a Falcon tenant, so correctness is pinned to CrowdStrike's
    published API models rather than to hand-written fixtures:
    tools/crowdstrike_schema.py derives the request/response shapes,
    tools/crowdstrike_schema_check.py fails
    when a fetcher reads a field the published model does not define,
    tools/crowdstrike_usage_check.py fails when a declared API scope isn't
    exercised (and the reverse), and examples/crowdstrike_mock_run.yaml runs the
    whole set against a schema-derived local double — no tenant, no credentials, no
    network egress. That covers the documented contract, not a live tenant's
    responses; prevention policies and Zero Trust Assessment are the two worth
    re-checking against a real tenant
    , as no public response samples exist for
    either.

  • docs/ksi_mapping.md — the full fetcher ↔ KSI
    mapping, readable in both directions, with FedRAMP's verbatim statements and
    NIST control crosswalk, and the open gaps called out as fetcher backlog.
    Generated by tools/gen_ksi_mapping.py; the generator is idempotent, so CI can
    fail on a diff to keep it honest.

  • Issue-report fetchers (kind: issue_report). A second collection kind for
    the file a scanner already produces — a Nessus export, a Wiz findings CSV —
    rather than a JSON payload asserting a configuration state. The runner writes
    those files unmodified to <run>/issue-reports/ (no envelope: Paramify's
    intake parser reads the vendor's own structure), records identity in a sidecar
    index, and a new uploader (paramify issues upload) posts each file to
    POST /assessment/{assessmentId}/intake. The assessment is chosen by name
    (paramify assessments list / select), the same way paramify programs target picks a program UUID without anyone typing one. Start from
    fetchers/_template_issue_report/ and
    docs/issue_report_fetchers.md. Written
    against Paramify REST API v0 spec 0.6.0
    (API documentation).

Changed

  • A failed fetcher now tells you why, in every category. Paramify used to
    show whoever was triaging Encountered 3 API failures during collection — a
    count, with no hint of which call broke. Two causes, one root: 103 fetchers
    across seven categories
    (aws 80, okta 8, knowbe4 4, k8s 3,
    paramify 3, rippling 3, checkov 2) never wrote $FETCHER_STATUS_FILE,
    so the runner fell back to the tail of stderr and metadata.error carried
    whatever the fetcher happened to log last; and the detail was being collected
    and then thrown away — every AWS fetcher recorded its causes into a temp
    failure log whose only reader, across all 80, was wc -l, and the exit trap
    deleted it.

    metadata.error now carries the actual cause and metadata.error_code one of
    seven closed values (auth_failed, not_authorized, target_unreachable,
    rate_limited, bad_config, partial_failure, internal_error). Forcing a
    credential failure on aws_guard_duty_findings reported
    Encountered 2 API failures during collection before. It now reports:

    {
      "error": "2 AWS API failure(s); first: aws sts get-caller-identity failed;aws guardduty list-detectors failed (exit=254): aws: [ERROR]: An error occurred (UnrecognizedClientException) when calling the ListDetectors operation: The security token included in the request is invalid.",
      "code": "partial_failure"
    }

    228 non-zero exit paths across the tree, 0 unreported. Note that the AWS
    family reports partial_failure uniformly — it counts and quotes the calls
    that broke rather than classifying why. Distinguishing auth_failed from
    rate_limited from not_authorized there needs per-call classification and is
    follow-up work; the reason text is what carries that information today.

    For fetcher authors this is a contract change. Reporting a failure is no
    longer something you hand-roll: there is now exactly one helper per runtime —
    fetchers/_lib/status.sh and
    fetchers/_lib/fetcher_status.py, both
    named report_failure — and
    docs/fetcher_contract.md mandates it. It logs
    and reports, so it is the whole failure path; logging inside the helper is
    what guarantees the reason is the last line on stderr, which is what the
    fallback reads. The same nine-line status write previously existed as 27
    copies under two names
    (report_failure and write_status) — 22 in
    individual fetchers, three in category-shared modules, and one in each
    scaffolding template — because the porting playbook printed those nine lines
    and told authors to paste them. The playbook and both templates now import the
    helper instead. A category-shared module may
    re-export it and must not reimplement it, which is how all 80 AWS fetchers
    were wired without a single per-file source line.

    One known regression: crowdstrike fetchers no longer set
    metadata.error_code. They passed their own strings (collection_error, a raw
    HTTP status) which the shared helper drops as outside the closed set. The error
    text is intact, and mapping those onto the seven real codes is a judgement
    call left to its own change.

  • Every fetcher's ksis re-keyed to the FedRAMP Consolidated Rules for 2026.
    FedRAMP replaced the numeric Phase One indicators (release 25.05C, 52 of them)
    with mnemonic ones (version 2026.07.14.01, 46 of them) — KSI-CNA-01 is now
    KSI-CNA-RNT. Every id changed, so every mapping in the repo did too. Beyond
    the re-key: TPR was deleted and SCR (Supply Chain Risk) added, INR became
    Incident Response, SVC-SIN absorbed both in-transit and at-rest encryption,
    IAM-APM absorbed both phishing-resistant MFA and passwordless, immutable
    infrastructure moved from CNA to CMT, and vulnerability management left
    MLA entirely.

    No action required for existing manifests or evidence sets. Manifests
    select fetchers by name (use: <fetcher>) and never referenced KSIs; no
    fetcher was renamed. evidence_set.reference_id is unchanged on all 176
    fetchers, so the uploader's get-or-create resolves to the same evidence sets —
    no duplicates, no re-linking. ksis is not carried in the envelope and is
    never transmitted to Paramify; it is repo-side reporting metadata read by
    paramify ksi.

    What does change: paramify ksi output, and the KSI ids shown in fetcher
    descriptions. Evidence sets created from now on drop the (KSI-XXX-NN) suffix
    from their display name — the uploader never renames, so sets that already
    exist in a tenant keep the name they were created with.

    Mappings are now documented as suggested / related rather than assertions
    that a fetcher satisfies an indicator on its own. Four indicators are left
    uncovered on purpose (SVC-VCM, MLA-ALA, RPL-TRC, SCR-MIT): the evidence
    does not exist yet, and an honest gap beats a mapping that has to be defended.
    Coverage is 32/36 config-evidenceable indicators.

  • Dropped "20x" from our own KSI labels in paramify ksi, the fetcher
    schema, and fetcher descriptions. The reference file now carries the exact
    release string, so it is the single source of truth for which release we
    measure against. FedRAMP 20x program deliverables (the VER reports) keep the
    name.

Deprecated

  • write_status in azure_common and gcp_common is now an alias for the
    shared report_failure. The 46 Azure and GCP call sites still using it keep
    working and are unchanged here; they log twice as a result (their own
    logger.error plus the helper's), which is cosmetic in the run log and does
    not affect what Paramify receives. Renaming those call sites and dropping the
    alias is one later pass, because the static conformance scan has to stop
    crediting the old name at the same moment the call sites change.

Fixed

  • TUI: arrow keys now work where the layout implies they should. left /
    right move along a button row — Textual's Button binds only enter, so
    every Yes/No and Save/Cancel dialog read as a left-right choice while
    answering to neither, leaving tab as the only way across. up / down
    typed into a filter box now walk the list it filters without taking focus out
    of the box, so you can keep narrowing while you move.

    Both are bound on the container rather than on the widgets, which is what
    keeps them safe: a key bubbles up from whatever has focus, so anything that
    already owns it keeps it. An Input's left / right still moves its text
    cursor; a Tree's...

Read more

v0.4.0-beta

v0.4.0-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 18 Aug 18:35
36e4003

[0.4.0-beta] - 2026-08-18

Breaking

  • KnowBe4 group- and campaign-scoped fetchers now require config. The group
    and campaign names these three fetchers match on were hardcoded to one tenant
    (see Fixed below); they now come from config_schema and are required, so
    a manifest that ran them before will now fail paramify validate — and the run
    — until the values are wired:

    Fetcher New required config
    knowbe4_high_risk_training high_risk_groups, role_specific_campaigns
    knowbe4_developer_specific_training developer_groups, developer_campaigns
    knowbe4_security_awareness_training security_awareness_campaigns

    Each takes a comma-separated list of names exactly as they read in your tenant,
    set with paramify manifest set-config <fetcher> <key>=<value> or through the
    matching KNOWBE4_* env var. retraining_interval_days was added at the same
    time but defaults to 365 and needs nothing. paramify doctor <manifest> names
    any that are still missing.

  • KnowBe4 evidence changed shape. A metric the fetcher could not measure is
    now null rather than 0, and training_module_summary for an empty tenant is
    {} rather than null; a new results.config_resolution block records what was
    requested, what matched, and what the tenant actually has. Re-check any
    validator or query that asserts on those fields
    — one written against
    "completion_rate": 0 will no longer match, which is the point: 0 used to mean
    both "measured, and it is zero" and "could not measure", and only the first of
    those is a finding.

Added

  • Azure — 27 fetchers (new category). Identity and access (Entra ID MFA,
    privileged roles, conditional access), compute and AKS posture, storage and
    database encryption at rest, Key Vault, App Service, monitoring and backup.
    Python against the official azure-mgmt-* SDKs — no az CLI at runtime — and
    authentication is DefaultAzureCredential, so a managed identity, a service
    principal or a cached az login all work and none of them is a key file.
    Fanned out per subscription. Installs with pip install -e '.[azure]' (23
    packages), deliberately not folded into [all]: it is heavier than
    everything else here combined and only matters if you run Azure. Majors are
    pinned, because six breaking changes across azure-mgmt majors each produced
    wrong or empty evidence rather than an error. Credential setup, and the
    tenant-vs-subscription scoping that the Entra fetchers need, are documented in
    the six themed example manifests
    (examples/azure_identity_and_access.yaml
    and siblings); the category has no README.md of its own yet.
  • GCP — 19 fetchers (new category). Compute and GKE posture, IAM and service
    accounts, KMS, Cloud Storage and Cloud SQL encryption at rest, BigQuery, logging
    and monitoring, DNS. Python against the official google-cloud-* clients, no
    gcloud at runtime, authenticating through Application Default Credentials —
    again no key file. Fanned out per project; a target that omits project collects
    from the ADC default ("collect where deployed"). pip install -e '.[gcp]' (12
    packages), also out of [all]. Credential setup in
    fetchers/gcp/README.md.
  • Paramify — 3 FedRAMP 20x VER report fetchers (new category). Accepted
    Vulnerability Info (VER-RPT-AVI), the Vulnerability Detail Report, and the
    historical VER-activity snapshot, generated from Paramify issue data and fanned
    out per program. Shared logic lives in fetchers/paramify/_shared/ver_common.py.
    Report-period and workspace-wide knobs (cert_package_uri, api_base_url,
    http_timeout) are category config under platforms.paramify.config rather than
    per-target secrets, so one value per workspace is set once.
  • Optional secrets — required: false on a declared secret. The ambient
    identity case: aws, azure, gcp and k8s all authenticate through a credential
    chain whose preferred links (an instance role, EKS IRSA or Pod Identity, a
    managed identity, workload identity, SSO, a cached CLI login) hand over no
    secret at all, while the same chain also accepts static keys. Every declared
    secret used to be mandatory, so those keys could not be declared without
    breaking the deployments that supply none — which meant paramify describe and
    the TUI reported that an AWS fetcher needed no credentials whatsoever. They are
    now declared and marked optional: advertised, resolvable from a ${env:...} ref
    like any other secret (so the runner masks them out of captured output), and
    simply not injected when a manifest omits them.
  • Category-level secrets: in fetchers/_categories/<name>.yaml — credentials
    shared by every fetcher in a category, declared once instead of repeated. Azure's
    service principal is three env vars used identically by all 27 of its fetchers.
    A per-fetcher secret of the same name still wins, mirroring how config_schema
    already merges; contract.effective_secrets() is the one place both the
    describe/TUI surface and the runner resolve through, so what is advertised and
    what is demanded cannot drift apart. secrets[].description was added alongside,
    and is what explains why an optional credential is optional.
  • $FETCHER_STATUS_FILE — an explicit channel for why a collection failed.
    A fetcher that fails writes {"error": "...", "code": "..."} there and the runner
    puts it in the envelope as metadata.error / metadata.error_code (a new
    optional envelope field; the envelope stays additive, so schema_version is
    still 1.0). Previously metadata.error was the tail of stderr, which assumes the
    last thing a fetcher logged is why it failed — false for the 16 fetchers whose
    final line is "Evidence saved to …", so a failed collection reported a success
    message as its failure reason. The stderr tail remains the fallback, so nothing
    had to migrate. Paramify surfaces that field to whoever is triaging. (#24)
  • paramify programs — a new command group over the Paramify workspace.
    programs list shows each program's readable name next to its project UUID;
    programs target selects programs (interactively, by name/id, or --all) and
    writes them as fanout targets, filling in the shared config they need. The API
    identifies programs by UUID while people know them by name; this closes that
    gap without anyone copying a UUID by hand. The shared values (--cert-uri,
    --report-from) are shown on every interactive run with what the manifest
    holds today as the prompt default and a note of where it comes from: enter
    keeps it and writes nothing, typing over it updates the category value. So the
    same command adds a program and rolls the report window forward, and neither
    requires opening the manifest to see what the next run will carry. Entries that
    resolve to different values get no default — either one offered as the answer
    would misreport the other.
  • program_name — an optional target field on the Paramify VER fetchers. The
    fetcher uses it for its evidence filename and the uploader for the artifact
    title, so per-program artifacts read as … - Alpha Cloud Services rather than
    a bare UUID. A UUID prefix stays in the filename because program names are not
    guaranteed unique.
  • requires: on a category — fetchers/_categories/<name>.yaml gains a
    requires: block naming the external binaries and the pip distributions its
    fetchers need, and paramify doctor checks them. With a manifest it checks only
    the categories that manifest actually uses, so a GitLab-only run is never told
    to install the aws CLI or 23 Azure SDKs. Version pins stay in
    requirements.txt, which remains the single source of truth for versions; a
    category file names only which distributions are its own. The declarations are
    themselves tested (tests/test_category_requires.py): an import or a
    shelled-out binary that nothing declares fails the suite, because doctor's
    report is only as good as what the category files say.
  • paramify doctor --probe — authenticates against each cloud category
    (aws, k8s, azure, gcp) and reports which identity answered: caller ARN
    and account, Azure principal and subscriptions, GCP account and project.
    Without it doctor can only see whether variables are set, which is nearly
    meaningless for credential chains whose preferred links — IRSA, workload
    identity, managed identity, a cached CLI login — set no variable at all, so
    doctor reported a clean bill of health and the run failed on auth. It also
    answers "as whom", the more common silent failure: credentials that work but
    point at the wrong account produce a successful run full of empty evidence.
    Opt-in because it is the only part of doctor that touches the network, each
    probe runs in a subprocess under a hard timeout, and a failed probe is reported
    without failing the command.
  • paramify doctor --require-upload — makes a missing API token count toward
    the exit code. Upload readiness (token presence and the destination URL) is
    always reported; gating is opt-in because collecting evidence without uploading
    it is a legitimate workflow that should not fail a preflight.
  • paramify upload asks for the API token when none is set and it is safe to
    ask — a real terminal at both ends, no CI, not --json. Reaching the upload
    step means the collection is already paid for, and this is a failure a person
    can fix on the spot rather than by re-running the whole thing. The value is used
    for that run and written nowhere; persisting a credential is the user's call, so
    it prints how instead of guessing at a file. paramify run says the same thing
    up front, advisory only, so you learn it in the first second rather than the
    last.

Changed

  • **paramify describe shows ea...
Read more

v0.3.1-beta

v0.3.1-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 28 Jul 20:08
42d3c0a

[0.3.1-beta] - 2026-07-28

Changed

  • Run manifests are no longer gitignored, and the repo no longer tracks a file at
    ./manifest.yaml. The manifest that used to sit there ships as
    example_manifest.yaml instead. Manifests describe which evidence you collect,
    so teams under a compliance program generally want them in version control —
    they hold no secret values, since ${env:VAR} resolves from the environment at
    run time. Previously /manifest.yaml and /manifests/ were listed in
    .gitignore and a manifest.yaml was tracked; because ignore rules don't
    apply to already-tracked files, that entry had no effect and edits to the
    shipped manifest were staged by default, conflicting on every upgrade.
    If you were relying on the tracked manifest.yaml, copy
    example_manifest.yaml to manifest.yaml, or pass --manifest explicitly.
    paramify manifest init and the manifests/ picker convention are unchanged.

Added

  • docs/private_mirror_workflow.md — keeping a
    private copy of this repo that still receives upstream releases, for teams whose
    fetcher work can't be public.

v0.3.0-beta

v0.3.0-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 23 Jul 18:48
b4a8ce3

Added

  • 13 Datadog fetchers (new category): Cloud SIEM detection rules & signals, SIEM
    operational configuration, log pipelines / indexes / archives, host & container
    inventory, agent check results, the APM service catalog, and incident records with
    timelines. Credential setup in fetchers/datadog/README.md.
  • paramify scripts sync — push each fetcher's entry script (fetcher.py /
    fetcher.sh) to Paramify and CONNECT it to that fetcher's evidence set, so the
    tenant records how each piece of evidence is generated. A provisioning step
    separate from paramify upload: it reconciles the tenant to the repo GitOps-style
    (marker-keyed identity in the script description, fetcher.yaml version as the
    update signal, a sha256 drift guard). Scoped to a manifest by default — it
    provisions scripts only for the fetchers you collect, mirroring how upload is
    run-scoped — with --all to push the whole catalog, plus --dry-run / --force /
    --reassociate / --json. Backed by the uploaders/paramify_scripts/ uploader.
    Only SCRIPT associations are automated; control / solution-capability / validator
    linkage stays Paramify-side.
  • docs/uploader_design.md — a dedicated uploader design
    doc covering both built uploaders and the shared evidence-set identity model, and
    a README section + docs-table entries pointing to it.

Changed

  • TUI Paramify tab redesigned into stacked evidence upload and scripts sync
    panels. Scripts sync gained a Preview action that runs a read-only dry-run and
    surfaces the per-fetcher plan (create / update / drift / noop) in a table — flagging
    which drifted scripts --force would push — and syncs the active manifest's fetchers.

Fixed

  • TUI: page keyboard shortcuts (ctrl+r / ctrl+u / ctrl+s) now fire regardless of
    which control is focused, and default focus lands in the active pane on mount, on tab
    switches (mouse clicks included), and after escape — previously they worked only
    right after a number-key tab switch.
  • TUI: the Add fetchers picker no longer drops a category once all its fetchers are in
    the manifest; already-added fetchers show greyed-out and non-selectable, so a
    fully-added category (e.g. datadog) stays visible.
  • TUI: the Paramify action row (Preview / Sync Scripts / force / reassociate) now uses
    uniform control sizes instead of content-sized widths and mismatched heights.

v0.2.1-beta

v0.2.1-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 10 Jul 16:52
f4071aa

What's Changed

  • chore(deploy): trim to a Docker-only bundle for public release by @21tmccauley in #11

Full Changelog: v0.2.0-beta...v0.2.1-beta

v0.2.0-beta

v0.2.0-beta Pre-release
Pre-release

Choose a tag to compare

@21tmccauley 21tmccauley released this 10 Jul 16:08
ac8e1f7

v0.2.0-beta — first public (beta) release

Paramify Fetchers collects compliance evidence from the tools you already run and writes it to disk as JSON; a separate uploader pushes that evidence to Paramify. Everything runs on your infrastructure — the fetchers never talk to Paramify directly. This is the first public cut: usable and tested end-to-end, but pre-1.0, so expect some rough edges and a contract that may still shift before 1.0.
Feedback and bug reports are very welcome.

Highlights

  • 100+ evidence fetchers across 8 categories — AWS (79), Okta, SentinelOne, KnowBe4, GitLab, Kubernetes, Rippling, and Checkov IaC scans.
  • Three ways to drive it — an interactive TUI, a machine-readable --json surface for AI agents and scripts, and the CLI directly. All go through one facade, so they behave identically.
  • Self-describing, schema-validated contract — every fetcher declares what it needs in fetcher.yaml; the runner treats them all uniformly.
  • Evidence envelope — every output is wrapped in {schema_version, metadata, payload} (envelope schema_version 1.0).
  • Upload stage — paramify upload pushes a run's evidence to Paramify.
  • Contract-gated CI + documented versioning — see docs/versioning.md.

Install

git clone https://github.com/paramify/paramify-fetchers.git
cd paramify-fetchers
python -m venv .venv && source .venv/bin/activate
pip install -e '.[all]'      # '[all]' includes the TUI
paramify tui                 # or: paramify run examples/demo.yaml  (no credentials)

Requires Python 3.10+.

This is a beta — what that means

  • Pre-1.0. The contract (fetcher / manifest / envelope schemas + the paramify CLI) may still change; breaking changes bump the minor version
  • Review category-specific config before trusting the evidence — some fetchers still carry environment-specific defaults (e.g. KnowBe4 training- campaign names) that you may need to adjust for your tenant.

Docs

Quickstart & usage → README · Contract → docs/fetcher_contract.md · Manifest
format → docs/run_manifest_reference.md · Releasing → docs/releasing.md.

Licensed under GPL-3.0-only.