Important
This project is currently not release-ready.
This is a project of the Apache Software Foundation and follows the ASF vulnerability handling process.
This document is for human security researchers, AI-assisted security researchers, and project maintainers handling vulnerability reports. Read it alongside the Apache Fineract Threat Model which governs the source banking application whose data this pipeline consumes.
Do not open a public GitHub issue for security vulnerabilities.
Report vulnerabilities privately using the ASF vulnerability reporting process:
- ASF Security team: security@apache.org
- Project mailing list (private): private@apache.org (Apache committers only)
- GitHub private reporting: Use the Security Advisories tab → "Report a vulnerability"
Include in your report:
- A description of the vulnerability and affected component
- Steps to reproduce or a proof-of-concept
- The potential impact and attack scenario
- Any suggested remediation
You will receive an acknowledgement within 72 hours. The ASF Security team coordinates disclosure timing with maintainers. Public disclosure happens only after a fix is available.
Source code repository: https://github.com/apache/fineract-business-intelligence
This document covers the fineract-business-intelligence data pipeline and BI layer:
| Component | Description |
|---|---|
Extractor (extractor/) |
Python service that reads from the Fineract PostgreSQL source DB via a read-only replica role and writes raw data to the analytics warehouse |
dbt models (dbt/) |
SQL transformation layer that builds marts and dimensions in the analytics warehouse |
Apache Superset (docker/superset/) |
Dashboard and visualisation layer connected to the analytics warehouse via a read-only reader role |
Docker Compose stack (compose.yaml) |
Local and CI orchestration of all services |
GitHub Actions workflows (.github/workflows/) |
CI pipeline including build, compilation, smoke tests, license, and security checks |
Seed / schema scripts (warehouse/seed/) |
SQL scripts that initialise the Fineract source schema for CI and development; not run in production against live data |
| Context | Description |
|---|---|
| Docker Compose (local dev) | docker compose up on a developer machine. All credentials from .env (copied from .env.example). Not suitable for production. |
| Docker Compose (CI) | Same stack, driven by GitHub Actions. Credentials are hardcoded development values; no production data is present. |
| Production (operator-managed) | Operator deploys services independently (e.g., Kubernetes, managed PostgreSQL). Credentials must be rotated; TLS must be configured. The compose.yaml is a reference, not a production config. |
- Analytics for microfinance operations: Branch managers and analysts view loan portfolio health, delinquency trends, PAR (Portfolio at Risk) metrics, and batch job status through Superset dashboards.
- Read-only extraction: The pipeline never writes to the Fineract source database. All mutations are on the analytics warehouse only.
- Incremental extraction: The extractor uses watermarks to extract only records modified since the last run, bounded by a COB (Close of Business) completion gate.
| Role | Trust level | Description |
|---|---|---|
| Operator / deployer | Full host / container access | Configures credentials, TLS, network isolation, secret management |
| Superset analyst (read-only) | Valid Superset session, no DB access | Branch manager, MFI analyst — sees dashboards only |
| Superset admin | Full Superset admin rights | Can add database connections, modify dashboards, access all data |
| CI runner | GitHub-hosted ubuntu-24.04 |
Ephemeral; no production data; dev-only credentials |
- Apache Fineract backend (Spring Boot, JDBC, Kafka, COB batch, core banking logic) — covered by the Fineract security team.
- Fineract source database internals — the extractor connects read-only; what happens inside the source DB is out of scope.
- Superset upstream vulnerabilities — bugs in the Apache Superset project should be reported to the Superset security team.
- Customer-facing portals — Superset is back-office only; bank customers are not users.
- Fineract source DB compromise: A compromised upstream DB will cause corrupted data to be extracted and propagated. Defence is Fineract's responsibility.
- Network-level DDoS against services: Volumetric DDoS mitigation is the operator's responsibility (CDN, cloud WAF, rate limiting at the load balancer).
- Physical access to the host machine: OS-level access is assumed to be already compromised.
- Supply-chain attack on Python/dbt/Superset packages: Dependency scanning
(Dependabot,
pip audit) is a downstream responsibility; this model assumes packages are not themselves compromised.
| Boundary | Description |
|---|---|
| Fineract source database | PostgreSQL instance owned by the Fineract application. Extractor connects as fineract_reader — a SELECT-only replica role. No write access is granted at any point. |
| Analytics warehouse | Separate PostgreSQL instance. Extractor writes to raw schema via analytics_loader role. dbt runs transformations via the same loader role. Superset reads via analytics_reader (SELECT on analytics schema only). |
| Superset metadata database | Stores dashboard definitions, user sessions, and dataset connection strings. Admin credentials must be rotated before any non-local deployment. |
| Docker internal network | Services communicate over a Docker bridge network (fineract-business-intelligence_default). Not TLS-encrypted by default. |
External Docker network (fineract_default) |
Declared external in compose.yaml; created by the operator before stack startup. Bridges the extractor to the Fineract source DB in the local dev setup. |
| CI runner | GitHub-hosted ubuntu-24.04 ephemeral runner. Contains development-only credentials; no production data. Isolated per run. |
| Docker socket | The extractor service mounts /var/run/docker.sock in compose.yaml. This grants the extractor container the ability to manage Docker on the host. See §9 for implications. |
[Apache Fineract DB — fineract_reader role, SELECT only]
|
| PostgreSQL / pg8000 (TLS optional)
v
[Extractor — Python service]
- COB gate: verifies batch_job_execution before extracting
- Watermark manager: incremental extraction by last_modified_on_utc
- Replica lag check: aborts if replica is too far behind
|
| PostgreSQL / pg8000
v
[Analytics Warehouse — raw schema]
|
| dbt SQL transformations
v
[Analytics Warehouse — analytics schema (marts, dims, presentations)]
|
| PostgreSQL / psycopg2 (read-only reader role)
v
[Apache Superset — dashboard layer]
|
| HTTPS (browser, TLS in production)
v
[End user — branch manager, MFI analyst]
- Extractor → Fineract source DB: Read-only replica user (
fineract_reader). Thebi_connector_sourceschema provides views that add syntheticcreated_on_utc/last_modified_on_utccolumns for tables that lack them natively (m_office,m_currency,m_product_loan). The extractor queries these views, not the underlying tables directly. - Extractor → Analytics warehouse:
analytics_loaderrole. Writes are scoped to therawschema. The loader role has no access toanalyticsschema where the marts live. - dbt → Analytics warehouse: Runs as
analytics_loader. Materialises models inanalyticsschema. Reads fromraw; writes toanalytics. - Superset → Analytics warehouse:
analytics_readerrole.SELECTonanalyticsschema only. Cannot readraw,meta, or other schemas. - CI runner → fineract-db container: Uses development-only bootstrap credentials
(
root/skdcnwauicn2ucnaecasdsajdnizucawencascdca). These are not production credentials and appear in plain text in.env.exampleandci.ymldeliberately — they are seeded into an ephemeral container and discarded after each run.
- Docker Engine and Docker Compose are installed and up to date.
- The host is not shared with untrusted workloads (no multi-tenant container platform without network isolation).
- The Docker socket is not exposed to the public network.
- In local dev: all services are on a private Docker bridge network, not reachable from outside the host by default.
- In production: the warehouse and Superset must be placed behind a firewall; neither should be reachable from the public internet without TLS termination and access control.
- All browser-to-Superset communication must be over TLS in production. The default
compose.yamlexposes Superset on HTTP port 8088 only.
- The watermark manager (
meta.watermarks) serialises extraction windows per tenant and source table. Concurrent extractor runs for the same tenant would cause undefined watermark state. The pipeline is designed for one run at a time per tenant.
- The extractor uses
datetime.now(timezone.utc)for pipeline state timestamps. Clock skew between the extractor host and the Fineract DB host can affect theextract_lookback_secondswindow. A skew larger thanREPLICA_LAG_THRESHOLD_SECONDS(default: 300 s) will cause the replica lag check to abort the run.
| Source | Trust | Notes |
|---|---|---|
Fineract source DB rows (via bi_connector_source views) |
Partially trusted — data integrity is Fineract's responsibility | Extractor uses parameterised queries (%s placeholders via pg8000); no raw string interpolation of source data into SQL |
.env file / container environment variables |
Operator-trusted | Whoever controls the host controls these values. Must not be committed to source control. |
dbt/profiles.yml env var defaults |
CI-trusted for PGUSER/PGPASSWORD defaults (ci); operator must override in production |
The fallback defaults exist only to allow dbt parse in CI without a live DB connection |
Superset dashboard configs (bootstrap_superset_assets.py) |
Operator-trusted | Loaded at Superset initialisation; a tampered bootstrap script could register malicious database connections |
| CI workflow inputs (branch names, PR authors) | Untrusted | Workflow uses contents: read only; no ${{ github.event.* }} variables are interpolated into run: steps |
Seed SQL (warehouse/seed/schema_fineract_source.sql) |
Trusted (static, version-controlled) | Runs only in CI / local dev against a throw-away container; not applied to production |
- Extraction batch size: Controlled by
extract_batch_sizeinAppConfig; batches are committed incrementally. Very large tables will produce many small commits — this is by design. - Pipeline interval: Default
PIPELINE_INTERVAL_SECONDS=3600. No rate limiting beyond this interval is enforced by the pipeline itself. - Superset query limits: Not configured by this project. Operators must configure
Superset's
ROW_LIMITand async query timeouts to prevent runaway queries from loading the warehouse.
| Adversary | Capability | What they are trying to do |
|---|---|---|
| Passive network observer | Can observe unencrypted traffic on the Docker network or between services | Capture database credentials or query results in transit if TLS is absent |
| Unauthenticated external user | Can reach Superset HTTP port if exposed | Access dashboards without credentials; exploit Superset login for credential stuffing |
| Authenticated Superset analyst | Valid Superset session, read-only role | Exfiltrate financial data beyond their permitted dashboards; pivot to warehouse via SQL Lab if enabled |
| Authenticated Superset admin | Full Superset admin rights | Register additional database connections (escalation); export all datasets; access connection strings stored in metadata DB |
| Malicious CI PR author | Can open a PR to the repository | Inject run: steps that exfiltrate CI secrets; exploit pull_request_target if misconfigured; introduce backdoored dependencies |
| Compromised extractor process | Code execution inside the extractor container | Read SOURCE_REPLICA_PASSWORD and WAREHOUSE_LOADER_PASSWORD from environment; connect to warehouse as loader and corrupt raw data; use Docker socket (if mounted) to escalate to host |
- Fineract DB admin: Full access to the source DB is assumed to be already authorised; this model cannot defend against it.
- Host OS / hypervisor attacker: Physical or OS-level access is assumed compromised.
- Browser zero-day exploiter: Superset UI browser attacks via unpatched engine vulnerabilities are not modelled.
- Supply-chain attacker (PyPI / npm): Compromise of a dependency package is out of scope; addressed by dependency scanning tooling.
- Read-only source access — the extractor connects to the Fineract DB as a
SELECT-only replica user (fineract_reader). No INSERT, UPDATE, or DELETE is possible on the source database from this pipeline. - Role separation in the warehouse — three distinct roles:
analytics_admin(DDL),analytics_loader(write toraw),analytics_reader(SELECT onanalyticsonly). Superset usesanalytics_readerand cannot reach raw or meta schemas. - Parameterised queries throughout the extractor — all source queries use
%splaceholders via pg8000; column and table names are quoted with_quote_identifier()which double-quotes and escapes the identifier. No raw string interpolation of source data into SQL. - COB gate — the extractor refuses to run if no
COMPLETEDbatch job execution is found within the configured lookback window, preventing extraction of inconsistent mid-batch state. - Replica lag check — aborts extraction if the source replica is too far behind the primary, preventing stale data from entering the warehouse silently.
- Watermark-based incremental extraction — extraction windows are bounded by
last_modified_on_utccursors stored inmeta.watermarks, preventing unbounded full-table scans after initial backfill. - Pinned GitHub Actions — all workflow action references are pinned to full commit SHAs to prevent supply-chain attacks via mutable version tags.
persist-credentials: falseon all checkout steps to limit credential exposure on CI runners.- Least-privilege CI permissions — workflow-level
permissions: contents: read. - Concurrency controls — CI workflow uses
cancel-in-progress: trueto prevent duplicate runs accumulating on the same branch. - Zizmor audit — all Actions workflow files are audited by Zizmor on every change for unpinned refs, script injection, and excessive permissions.
- TLS between services — Docker Compose uses an internal bridge network without TLS. Container-to-container credentials and query results are transmitted in plaintext. Production deployments must add TLS or mTLS between all services.
- Docker socket isolation — the extractor service mounts
/var/run/docker.sockincompose.yaml. This gives the extractor container full Docker control over the host (equivalent to root). In production, remove this mount unless the pipeline management scripts genuinely require it; if required, use Docker's authorisation plugin or rootless Docker instead. - Superset MFA — multi-factor authentication for Superset is not configured. Enforce
at the Superset layer in production (
AUTH_TYPE, LDAP, or SAML integration). - Superset SQL Lab restriction — SQL Lab is not disabled by default. An analyst with SQL Lab access can run arbitrary SELECT queries against the warehouse reader connection. Restrict SQL Lab access to trusted roles in production Superset configuration.
- Warehouse encryption at rest — not configured in the Docker Compose setup. Production PostgreSQL must use filesystem-level or Transparent Data Encryption.
- Audit log for pipeline runs — no tamper-resistant audit trail of extractor runs
or dbt executions beyond container logs and the
meta.pipeline_statetable (which is mutable by the loader role). - Network egress restrictions — the extractor has no outbound firewall rules. In production, restrict egress to the warehouse host and source DB host only.
- Secret manager integration — credentials are passed via environment variables.
Production deployments should use a secret manager (HashiCorp Vault, AWS Secrets
Manager, Kubernetes Secrets) rather than plain
.envfiles. - CI credential rotation — the development PostgreSQL password
(
skdcnwauicn2ucnaecasdsajdnizucawencascdca) appears in plain text in.env.exampleandci.yml. This is intentional: it is a development-only seed credential for an ephemeral CI container containing no real data. It must not be used in any non-CI deployment. See §10 for the production credential requirement.
- Warehouse loader role abuse: If
WAREHOUSE_LOADER_PASSWORDis leaked, an attacker can corrupt or delete raw extraction data. Theanalyticsschema is protected (reader role only), but raw data integrity is lost. - Superset metadata DB access via admin credentials: If
WAREHOUSE_ADMIN_PASSWORDis leaked, an attacker can read all Superset dashboard configs, database connection strings, and user session data stored in the metadata DB. - Docker socket escalation: A compromised extractor process with access to
/var/run/docker.sockcan spawn privileged containers and escape to the host. This is a known Docker architecture limitation; see §9 mitigation above. - Fineract source DB poisoning: If the upstream Fineract DB is compromised before extraction, malicious data will propagate through the pipeline to dashboards. The pipeline has no integrity-verification layer on source data.
-
Replace all
.env.examplecredentials before any non-local deployment. Every password in.env.exampleis a placeholder — none may be used in production. -
Remove the Docker socket mount from the extractor service in
compose.yamlunless the pipeline management scripts genuinely require Docker access. If required, use the minimum necessary Docker API scope. -
Terminate TLS in front of Superset. The default
compose.yamlexposes Superset on HTTP port 8088 only. -
Set
SUPERSET_SECRET_KEYto a cryptographically random value. The.env.exampleplaceholder (change_me_before_production_use_a_random_32_byte_hex) must be replaced. A compromised secret key allows session forgery for all Superset users.python -c "import secrets; print(secrets.token_hex(32))" -
Restrict network access — neither the warehouse nor the Fineract source DB should be reachable from the public internet. Place them on private subnets.
-
Disable or restrict Superset SQL Lab for analyst roles. SQL Lab gives direct query access to the warehouse reader connection.
-
Enable Superset MFA for admin accounts.
-
Use a secret manager for all credentials. Do not use plain
.envfiles in production. -
Rotate credentials on a regular schedule and after any personnel change.
-
Monitor pipeline state via the
meta.pipeline_statetable and container logs, or integrate with a log aggregation platform for failure alerting. -
Run
pip auditagainst the extractor's dependencies before production deployment to detect known CVEs in Python packages.
-
Using
.env.examplecredentials in production. The bootstrap password (skdcnwauicn2ucnaecasdsajdnizucawencascdca) is public, appears in the repository, and is known to anyone who has read this file. Any deployment using it is exploitable by any reader of this repository. -
Exposing Superset on HTTP without TLS. Port 8088 in
compose.yamlis HTTP only. All session cookies, credentials, and dashboard data are transmitted in plaintext to any network observer. -
Leaving the Docker socket mounted in production. The
compose.yamlmount of/var/run/docker.sockinto the extractor container is a development convenience for runningdocker composecommands from within the pipeline. In a production deployment, this grants the extractor (and any code it executes) full Docker host control. -
Deploying
compose.yamldirectly to production without changes. The file is optimised for local development: no TLS, hardcoded dev credential defaults, volume paths suited to local developer machines, and the Docker socket mount. It is not a production-ready deployment manifest. -
Enabling SQL Lab for all Superset users. Analysts who should only see pre-built dashboards gain the ability to run arbitrary queries against the warehouse if SQL Lab is not restricted by role.
-
Running multiple extractor instances for the same tenant simultaneously. The watermark manager uses per-table, per-tenant rows in
meta.watermarksbut does not hold a distributed lock. Concurrent runs will produce undefined watermark state and may load duplicate or missing rows.
The following changes should trigger a revision of this threat model:
- Write-back to Fineract source DB — if any component is granted INSERT/UPDATE privileges on the Fineract source DB, the read-only source trust boundary is broken and the entire model must be reconsidered.
- Addition of a public-facing API layer — e.g., a REST API exposing warehouse data directly. This introduces a new trust boundary and attack surface not covered here.
- Multi-tenant SaaS deployment — if a single warehouse instance serves multiple
organisations, tenant isolation in the
rawandanalyticsschemas must be formally modelled (currently assumed single-tenant per warehouse instance). - New extraction targets — adding extraction of PII beyond what is currently extracted (client names, dates of birth, account numbers) requires a PII inventory review and potentially a GDPR/data-protection impact assessment.
- Streaming / CDC extraction — replacing batch watermark extraction with Change Data Capture (Debezium, logical replication) introduces replication slot management, new failure modes, and potential for replay attacks.
- Superset embedded analytics — if Superset is embedded in an external web application via the Embedded SDK, the browser trust boundary changes and CSRF/iframe protections must be modelled.
- Removal of the COB gate — the
_ensure_cob_completedcheck is a data-integrity gate, not just a scheduling convenience. Removing it without an equivalent guarantee creates a window where partially-committed Fineract batches are extracted. - New CVE affecting pg8000, psycopg2, dbt-core, or Apache Superset that cannot be
cleanly routed to one of the §13 dispositions — this indicates a
MODEL-GAPand requires model revision.
Use these dispositions when evaluating a security report before escalating to the ASF Security team.
| Disposition | Meaning | Licensed by |
|---|---|---|
VALID |
Violates a property the project claims, via an in-scope adversary and in-scope input | §8, §6, §7 |
VALID-HARDENING |
No §8 property is violated, but the finding makes a §11 misuse easier or exposes a defence-in-depth gap. Reported privately; fixed at maintainer discretion; typically no CVE. | §11 |
OUT-OF-MODEL: upstream-layer |
Finding targets the Fineract backend, Superset upstream, or PostgreSQL engine — not this pipeline. Route to the relevant upstream project's security team. | §3 |
OUT-OF-MODEL: trusted-input |
Requires attacker control of a parameter the model marks as operator-trusted (.env, container env vars, compose.yaml, Superset admin account). |
§6 |
OUT-OF-MODEL: adversary-not-in-scope |
Requires an attacker capability the model excludes (physical host access, Docker socket access not granted in production, supply-chain compromise of pip packages). | §7 |
OUT-OF-MODEL: unsupported-deployment |
Only manifests under a deployment the project does not support (e.g., using compose.yaml in production without changes, using dev credentials in production). |
§4, §11 |
BY-DESIGN: property-disclaimed |
Concerns a property the project explicitly does not provide (TLS between services, Docker socket isolation, SQL Lab restriction, audit log, storage encryption at rest). | §9 |
KNOWN-NON-FINDING |
Matches a known misuse pattern documented in §11 or a CI-only credential known to be public. | §11 |
MODEL-GAP |
Cannot be cleanly routed to any of the above. Triggers §12 revision and requires model update before triage can conclude. | §12 |
The following automated security gates run on every pull request and push via GitHub Actions.
All workflows pin action references to full commit SHAs and use persist-credentials: false.
Workflow: .github/workflows/ci.yml
Trigger: push on any branch; pull_request on main and develop
Two-stage pipeline:
- Stage 1 — compilation checks: Verifies
dbt parsesucceeds (all model references resolve, env var defaults are present), that the Extractor Python package installs cleanly, and that the Apache Superset bootstrap assets script is syntactically valid. - Stage 2 — smoke tests: Brings up the full Docker Compose stack, seeds the Fineract
schema, creates
bi_connector_sourceviews, runs the extractor in backfill mode, runsdbt run, and asserts 12 data-integrity invariants against the warehouse.
Security-relevant properties of the CI workflow:
permissions: contents: readonly — no write, deploy, or secret access.cancel-in-progress: true— prevents credential or resource accumulation from orphaned runs.- External Docker network (
fineract_default) created before stack startup; not inherited from a previous run. - Stale volumes cleaned up with
docker compose down -vbefore each run to prevent data leakage between runs. - No
pull_request_targettrigger — untrusted PR code cannot access repository secrets.
Workflow: .github/workflows/zizmor.yml
Trigger: push/PR on any branch when .github/workflows/** files change
Zizmor audits all GitHub Actions workflow YAML files for security misconfigurations, including:
- Unpinned action references (all actions must be pinned to a full commit SHA)
- Script injection via
github.event.*context variables inrun:steps - Excessive workflow permissions
- Dangerous
pull_request_targetpatterns
All action references in this repository are pinned to SHA hashes. Tag-based references
(@v3, @v4) are not permitted and will fail the Zizmor check.
Results are uploaded to GitHub's Security tab as SARIF for review.
Workflow: .github/workflows/codeql.yml
Trigger: push/PR to main; weekly scheduled scan
Languages: python, actions
GitHub CodeQL performs deep static analysis on the Python extractor code and on the GitHub Actions workflow files. It catches:
- SQL injection patterns in Python DB code
- Command injection in shell
run:steps - Insecure use of
subprocess,eval,exec - Workflow-level injection via untrusted inputs
Results appear in GitHub's Security tab.
Workflow: .github/workflows/apache-rat.yml
Scans every file for an Apache License 2.0 header. Fails if any project-owned file is missing a header. Prevents unlicensed third-party code from entering the repository.
Workflow: .github/workflows/asf-allowlist-check.yml
Verifies that all dependencies are on the ASF-approved licence allowlist. Blocks GPL, LGPL, AGPL, and other ASF-incompatible licences.
Workflow: .github/workflows/license-check.yml
Per-file Apache header enforcement across source files using a custom script.
| Secret | Where configured | CI value | Production requirement |
|---|---|---|---|
SOURCE_BOOTSTRAP_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate; never commit |
SOURCE_REPLICA_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate; use a dedicated read-only role |
WAREHOUSE_ADMIN_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate; restrict to DDL operations only |
WAREHOUSE_LOADER_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate |
WAREHOUSE_READER_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate; SELECT-only grants enforced |
SUPERSET_SECRET_KEY |
.env / CI .env.example |
Public placeholder | Must be a random 32-byte hex value |
SUPERSET_ADMIN_PASSWORD |
.env / CI .env.example |
Public placeholder | Rotate; enforce strong password policy |
PGPASSWORD (CI fineract-db) |
ci.yml plain text |
skdcnwauicn2ucnaecasdsajdnizucawencascdca |
Not applicable — CI-only, ephemeral container, no real data |
The PGPASSWORD in ci.yml is intentionally plain text. It is the PostgreSQL bootstrap
password for an ephemeral container seeded with synthetic test data. It is not a secret;
it is the same value as SOURCE_BOOTSTRAP_PASSWORD in .env.example which is already
public in the repository. Any reader of this repository already has this value.
Generate a secure SUPERSET_SECRET_KEY for production:
python -c "import secrets; print(secrets.token_hex(32))"All contributors — human or AI-assisted — must satisfy the following before a PR can merge.
| Responsibility | How to satisfy it |
|---|---|
| Apache License 2.0 header on every new file | Copy the header block from any existing source file of the same type. Apache RAT will fail without it. |
| No hard-coded credentials or secrets | Use environment variables with .env / container env. The only exception is the CI development seed password documented in §15. |
No new pull_request_target triggers |
This trigger grants secrets access to untrusted PR code. Zizmor will flag it; do not add it. |
| All new Action references pinned to SHA | Tag-based refs (@v4) are not permitted. Zizmor enforces this. |
| Parameterised queries for any new DB access | Do not use f-strings or string concatenation to build SQL with user-supplied or source-data values. Use %s placeholders. |
| ASF-compatible dependency licences | Before adding a Python package, verify its licence is in the ASF Category A list (Apache-2.0, MIT, BSD-2-Clause, BSD-3-Clause, ISC, PSF). |
| No Docker socket mount in new services | Do not add /var/run/docker.sock mounts to new services. If genuinely required, document the justification in the PR and in §9. |
PRs that touch the files below require explicit maintainer sign-off on the security implications before merge:
| File / area | Why |
|---|---|
extractor/extractor.py |
Source query construction, watermark logic, upsert SQL — SQL injection surface |
extractor/config.py |
Credential loading from environment; any change could leak secrets or weaken role separation |
scripts/bootstrap_source.sh |
Creates bi_connector_source views and grants; a bug here could grant excessive access to the source DB |
docker/fineract-postgresql/initdb/ |
Database initialisation scripts; sets up roles and grants on the source DB |
docker/postgres-warehouse/initdb/ |
Warehouse role setup; defines the loader/reader permission boundaries |
compose.yaml |
Service network config, credential env vars, Docker socket mount, volume mounts |
dbt/profiles.yml |
Database connection credentials; env var defaults must not weaken production security |
.github/workflows/ |
Any workflow change is also audited by Zizmor and CodeQL (actions language) |
- When you add a feature that changes the attack surface (see §12 for the trigger list), update this document in the same PR.
- When CI flags a finding you believe is a false positive, document the rationale in the PR description. Do not suppress linter rules or audit findings silently.
- When a new CVE in pg8000, dbt-core, or Apache Superset is published, open a tracking issue within 48 hours and reference the relevant §13 disposition.
This is an Apache Software Foundation project. Every file and every dependency must be compatible with the ASF Licensing Policy.
Every project-owned source file must carry the full Apache License 2.0 header. Apache RAT
and the license-check workflow enforce this on every PR. Files legitimately excluded from
RAT (generated assets, lockfiles, binary images) must be listed in .rat-excludes with a
documented justification.
To add a header to a new file, copy the block from any existing file of the same type.
Before adding any Python package to extractor/requirements.txt or any dbt package to
dbt/packages.yml, verify its licence is in the ASF Category A list:
| SPDX identifier | ASF category |
|---|---|
Apache-2.0 |
Category A — free to use |
MIT |
Category A — free to use |
BSD-2-Clause |
Category A — free to use |
BSD-3-Clause |
Category A — free to use |
ISC |
Category A — free to use |
PSF-2.0 |
Category A — free to use |
The following are blocked:
| Blocked family | Examples | Reason |
|---|---|---|
| Copyleft (strong) | GPL-2.0, GPL-3.0, AGPL-3.0 | Incompatible with ALv2 |
| Copyleft (weak) | LGPL-2.0, LGPL-2.1, LGPL-3.0 | Incompatible when statically linked |
| Non-commercial | CC-BY-NC-* | Restricts commercial use |
| Proprietary / EULA | various | Cannot be distributed under ALv2 |
Caution
Do not add a package with a blocked licence to any allowlist override. Find an ASF-compatible alternative, or raise a formal ASF legal exception request on the mailing list.
.asf.yaml enforces the following on the main branch:
| Rule | Setting |
|---|---|
| Signed commits required | required_signatures: true |
| Force push prohibited | restrict_force_push: true |
| Branch deletion prohibited | restrict_deletion: true |
| Minimum approving reviews | 1 |
| Conversations must be resolved | required_conversation_resolution: true |
Do not add open questions here. Raise sensitive questions via the ASF security reporting process (§1). Raise non-sensitive questions on the mailing list, in GitHub Discussions, or in a PR comment.