Repository navigation
Releases: paramify/paramify-fetchers
Release list
v0.5.1-beta
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 asaws ... 2>/dev/nulland 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 hardcodedpartial_failure, sometadata.error_codecarried no
information for the largest category in the repo.Both are fixed.
metadata.errornow carries the AWS error text behind the
calls that failed, andmetadata.error_codeis 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
codeis what the not-enabled classification work and the
deleted-mid-scan decision were both waiting on.No call site was rewritten.
awsin
fetchers/aws/_shared/aws.shis 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 the2>"$_ERR"+greppattern the
not-enabled check depends on still works, synchronously. The one constraint
this adds: a fetcher must reach the CLI as plainaws, nevercommand awsor
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.pypins the current wordings verbatim. -
A not-enabled service still exits 0. The wrapper captures the
SubscriptionRequiredExceptionstderr 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_unavailableis 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' '; ', andtrmaps 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-networkmoves from<32to<33and
azure-mgmt-recoveryservicesbackupfrom<11to<12, in both
pyproject.tomlandrequirements.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.
Everyazure-mgmtmajor 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-bearingazure-mgmt-monitor<7and passed all
twelve checks, while 7.0.0 removes thediagnostic_settingsoperation 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 withpytest.importorskipand 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 onlyAzure and GCP need their own extras (.[azure], .[gcp]) — see the README.
v0.5.0-beta
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-Aftercontract on 429s. Commercial and GovCloud both supported —
cloud_regionselects a commercial region orus-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.pyderives the request/response shapes,
tools/crowdstrike_schema_check.pyfails
when a fetcher reads a field the published model does not define,
tools/crowdstrike_usage_check.pyfails when a declared API scope isn't
exercised (and the reverse), andexamples/crowdstrike_mock_run.yamlruns 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 bytools/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 wayparamify programs targetpicks 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 triagingEncountered 3 API failures during collection— a
count, with no hint of which call broke. Two causes, one root: 103 fetchers
across seven categories (aws80,okta8,knowbe44,k8s3,
paramify3,rippling3,checkov2) never wrote$FETCHER_STATUS_FILE,
so the runner fell back to the tail of stderr andmetadata.errorcarried
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, waswc -l, and the exit trap
deleted it.metadata.errornow carries the actual cause andmetadata.error_codeone of
seven closed values (auth_failed,not_authorized,target_unreachable,
rate_limited,bad_config,partial_failure,internal_error). Forcing a
credential failure onaws_guard_duty_findingsreported
Encountered 2 API failures during collectionbefore. 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 reportspartial_failureuniformly — it counts and quotes the calls
that broke rather than classifying why. Distinguishingauth_failedfrom
rate_limitedfromnot_authorizedthere 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.shand
fetchers/_lib/fetcher_status.py, both
namedreport_failure— and
docs/fetcher_contract.mdmandates 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_failureandwrite_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-filesourceline.One known regression:
crowdstrikefetchers 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
ksisre-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-01is now
KSI-CNA-RNT. Every id changed, so every mapping in the repo did too. Beyond
the re-key:TPRwas deleted andSCR(Supply Chain Risk) added,INRbecame
Incident Response,SVC-SINabsorbed both in-transit and at-rest encryption,
IAM-APMabsorbed both phishing-resistant MFA and passwordless, immutable
infrastructure moved fromCNAtoCMT, and vulnerability management left
MLAentirely.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_idis unchanged on all 176
fetchers, so the uploader's get-or-create resolves to the same evidence sets —
no duplicates, no re-linking.ksisis 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 ksioutput, 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_statusinazure_commonandgcp_commonis now an alias for the
sharedreport_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.errorplus 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/
rightmove along a button row — Textual'sButtonbinds onlyenter, so
every Yes/No and Save/Cancel dialog read as a left-right choice while
answering to neither, leavingtabas 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. AnInput'sleft/rightstill moves its text
cursor; aTree's...
v0.4.0-beta
[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 fromconfig_schemaand are required, so
a manifest that ran them before will now failparamify validate— and the run
— until the values are wired:Fetcher New required config knowbe4_high_risk_traininghigh_risk_groups,role_specific_campaignsknowbe4_developer_specific_trainingdeveloper_groups,developer_campaignsknowbe4_security_awareness_trainingsecurity_awareness_campaignsEach takes a comma-separated list of names exactly as they read in your tenant,
set withparamify manifest set-config <fetcher> <key>=<value>or through the
matchingKNOWBE4_*env var.retraining_interval_dayswas 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
nownullrather than0, andtraining_module_summaryfor an empty tenant is
{}rather thannull; a newresults.config_resolutionblock 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": 0will no longer match, which is the point:0used 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 officialazure-mgmt-*SDKs — noazCLI at runtime — and
authentication isDefaultAzureCredential, so a managed identity, a service
principal or a cachedaz loginall work and none of them is a key file.
Fanned out per subscription. Installs withpip 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 acrossazure-mgmtmajors 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 noREADME.mdof 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 officialgoogle-cloud-*clients, no
gcloudat runtime, authenticating through Application Default Credentials —
again no key file. Fanned out per project; a target that omitsprojectcollects
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 infetchers/paramify/_shared/ver_common.py.
Report-period and workspace-wide knobs (cert_package_uri,api_base_url,
http_timeout) are category config underplatforms.paramify.configrather than
per-target secrets, so one value per workspace is set once. - Optional secrets —
required: falseon 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 meantparamify describeand
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:infetchers/_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 howconfig_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[].descriptionwas 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 asmetadata.error/metadata.error_code(a new
optional envelope field; the envelope stays additive, soschema_versionis
still 1.0). Previouslymetadata.errorwas 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 listshows each program's readable name next to its project UUID;
programs targetselects 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 Servicesrather 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>.yamlgains a
requires:block naming the external binaries and the pip distributions its
fetchers need, andparamify doctorchecks 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 uploadasks 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 runsays the same thing
up front, advisory only, so you learn it in the first second rather than the
last.
Changed
- **
paramify describeshows ea...
v0.3.1-beta
[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.yamlinstead. 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.yamland/manifests/were listed in
.gitignoreand amanifest.yamlwas 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 trackedmanifest.yaml, copy
example_manifest.yamltomanifest.yaml, or pass--manifestexplicitly.
paramify manifest initand themanifests/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
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 infetchers/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 fromparamify upload: it reconciles the tenant to the repo GitOps-style
(marker-keyed identity in the script description,fetcher.yamlversionas the
update signal, a sha256 drift guard). Scoped to a manifest by default — it
provisions scripts only for the fetchers you collect, mirroring howuploadis
run-scoped — with--allto push the whole catalog, plus--dry-run/--force/
--reassociate/--json. Backed by theuploaders/paramify_scripts/uploader.
OnlySCRIPTassociations 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--forcewould 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 afterescape— 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
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 — 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
--jsonsurface 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}(envelopeschema_version1.0). - Upload stage —
paramify uploadpushes 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.