chore: harden audit checks and issue taxonomy
This commit is contained in:
15
.env.example
15
.env.example
@@ -2,17 +2,24 @@
|
|||||||
# Copy to a deployment-local .env or secret store. Do not commit populated secrets.
|
# Copy to a deployment-local .env or secret store. Do not commit populated secrets.
|
||||||
|
|
||||||
APP_ENV=production
|
APP_ENV=production
|
||||||
|
# Live graph changes are useful in development. Production should apply saved
|
||||||
|
# module state through a coordinated restart of all API and worker processes.
|
||||||
|
GOVOPLAN_MODULE_LIVE_APPLY_ENABLED=
|
||||||
GOVOPLAN_INSTALL_PROFILE=self-hosted
|
GOVOPLAN_INSTALL_PROFILE=self-hosted
|
||||||
MASTER_KEY_B64=<generate-with-govoplan-config-env-template-generate-secrets>
|
MASTER_KEY_B64=<generate-with-govoplan-config-env-template-generate-secrets>
|
||||||
|
|
||||||
DATABASE_URL=postgresql+psycopg://govoplan:change-me@127.0.0.1:5432/govoplan
|
DATABASE_URL=postgresql+psycopg://govoplan:change-me@127.0.0.1:5432/govoplan
|
||||||
GOVOPLAN_DATABASE_URL_PGTOOLS=postgresql://govoplan:change-me@127.0.0.1:5432/govoplan
|
GOVOPLAN_DATABASE_URL_PGTOOLS=postgresql://govoplan:change-me@127.0.0.1:5432/govoplan
|
||||||
|
GOVOPLAN_DB_POOL_SIZE=5
|
||||||
|
GOVOPLAN_DB_MAX_OVERFLOW=10
|
||||||
|
GOVOPLAN_DB_POOL_TIMEOUT_SECONDS=30
|
||||||
|
GOVOPLAN_DB_POOL_RECYCLE_SECONDS=1800
|
||||||
|
|
||||||
ENABLED_MODULES=tenancy,organizations,identity,access,admin,dashboard,policy,audit,files,mail,campaigns,calendar,poll,scheduling,connectors,datasources,dataflow,workflow,views,notifications,docs,ops
|
ENABLED_MODULES=tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,files,mail,campaigns,calendar,poll,scheduling,connectors,datasources,dataflow,workflow,views,postbox,notifications,docs,ops
|
||||||
|
|
||||||
CELERY_ENABLED=true
|
CELERY_ENABLED=true
|
||||||
REDIS_URL=redis://127.0.0.1:6379/0
|
REDIS_URL=redis://127.0.0.1:6379/0
|
||||||
CELERY_QUEUES=send_email,append_sent,notifications,calendar,default
|
CELERY_QUEUES=send_email,append_sent,notifications,calendar,dataflow,events,default
|
||||||
CALENDAR_OUTBOX_TERMINAL_RETENTION_DAYS=90
|
CALENDAR_OUTBOX_TERMINAL_RETENTION_DAYS=90
|
||||||
|
|
||||||
GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS=false
|
GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS=false
|
||||||
@@ -24,10 +31,14 @@ GOVOPLAN_HTTP_MAX_REQUEST_BODY_BYTES=536870912
|
|||||||
GOVOPLAN_HTTP_HSTS_SECONDS=31536000
|
GOVOPLAN_HTTP_HSTS_SECONDS=31536000
|
||||||
|
|
||||||
AUTH_LOGIN_THROTTLE_ENABLED=true
|
AUTH_LOGIN_THROTTLE_ENABLED=true
|
||||||
|
AUTH_ACTIVITY_TOUCH_INTERVAL_SECONDS=300
|
||||||
AUTH_LOGIN_THROTTLE_IDENTITY_LIMIT=10
|
AUTH_LOGIN_THROTTLE_IDENTITY_LIMIT=10
|
||||||
AUTH_LOGIN_THROTTLE_CLIENT_LIMIT=100
|
AUTH_LOGIN_THROTTLE_CLIENT_LIMIT=100
|
||||||
AUTH_LOGIN_THROTTLE_WINDOW_SECONDS=900
|
AUTH_LOGIN_THROTTLE_WINDOW_SECONDS=900
|
||||||
AUTH_LOGIN_THROTTLE_REDIS_RETRY_SECONDS=30
|
AUTH_LOGIN_THROTTLE_REDIS_RETRY_SECONDS=30
|
||||||
|
# Production startup fails without Redis unless this explicit single-process
|
||||||
|
# risk acknowledgement is enabled.
|
||||||
|
GOVOPLAN_ALLOW_PROCESS_LOCAL_LOGIN_THROTTLE=false
|
||||||
|
|
||||||
CORS_ORIGINS=https://govoplan.example.org
|
CORS_ORIGINS=https://govoplan.example.org
|
||||||
GOVOPLAN_TRUSTED_HOSTS=govoplan.example.org
|
GOVOPLAN_TRUSTED_HOSTS=govoplan.example.org
|
||||||
|
|||||||
@@ -149,6 +149,12 @@
|
|||||||
"description": "GovOPlaN core runner, shared primitives, shell, or extension points.",
|
"description": "GovOPlaN core runner, shared primitives, shell, or extension points.",
|
||||||
"exclusive": false
|
"exclusive": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "module/dashboard",
|
||||||
|
"color": "1d76db",
|
||||||
|
"description": "GovOPlaN Dashboard module behavior or integration.",
|
||||||
|
"exclusive": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "module/dataflow",
|
"name": "module/dataflow",
|
||||||
"color": "1d76db",
|
"color": "1d76db",
|
||||||
@@ -167,6 +173,12 @@
|
|||||||
"description": "GovOPlaN Dms module behavior or integration.",
|
"description": "GovOPlaN Dms module behavior or integration.",
|
||||||
"exclusive": false
|
"exclusive": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "module/docs",
|
||||||
|
"color": "c5def5",
|
||||||
|
"description": "GovOPlaN Docs module behavior or integration.",
|
||||||
|
"exclusive": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "module/dist-lists",
|
"name": "module/dist-lists",
|
||||||
"color": "0e8a16",
|
"color": "0e8a16",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
-e ../govoplan-dataflow
|
-e ../govoplan-dataflow
|
||||||
-e ../govoplan-workflow
|
-e ../govoplan-workflow
|
||||||
-e ../govoplan-views
|
-e ../govoplan-views
|
||||||
|
-e ../govoplan-postbox
|
||||||
-e ../govoplan-poll
|
-e ../govoplan-poll
|
||||||
-e ../govoplan-scheduling
|
-e ../govoplan-scheduling
|
||||||
-e ../govoplan-notifications
|
-e ../govoplan-notifications
|
||||||
@@ -37,6 +38,7 @@ idna>=3.15
|
|||||||
jsonschema>=4,<5
|
jsonschema>=4,<5
|
||||||
pip>=26.1.2
|
pip>=26.1.2
|
||||||
pip-audit>=2.9,<3
|
pip-audit>=2.9,<3
|
||||||
pytest>=8,<9
|
pytest>=9.0.3,<10
|
||||||
|
pygments>=2.20,<3
|
||||||
python-multipart>=0.0.31
|
python-multipart>=0.0.31
|
||||||
ruff>=0.14,<1
|
ruff>=0.14,<1
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# Test-harness dependencies used against immutable release source tags.
|
# Test-harness dependencies used against immutable release source tags.
|
||||||
# Keep these separate from requirements-release.txt so they are not part of the
|
# Keep these separate from requirements-release.txt so they are not part of the
|
||||||
# deployable product dependency set.
|
# deployable product dependency set.
|
||||||
pytest>=8,<9
|
pytest>=9.0.3,<10
|
||||||
|
pygments>=2.20,<3
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ PY
|
|||||||
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-dataflow/tests
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-dataflow/tests
|
||||||
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-workflow/tests
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-workflow/tests
|
||||||
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-views/tests
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-views/tests
|
||||||
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-dashboard/tests
|
||||||
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-postbox/tests
|
||||||
"$PYTHON" "$META_ROOT/tools/checks/check-datasource-composition.py"
|
"$PYTHON" "$META_ROOT/tools/checks/check-datasource-composition.py"
|
||||||
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-mail/tests
|
"$PYTHON" -m unittest discover -s /mnt/DATA/git/govoplan-mail/tests
|
||||||
"$PYTHON" -m unittest tests.test_api_smoke.ApiSmokeTests.test_mailbox_message_listing_reports_total_count
|
"$PYTHON" -m unittest tests.test_api_smoke.ApiSmokeTests.test_mailbox_message_listing_reports_total_count
|
||||||
@@ -92,6 +94,12 @@ cd /mnt/DATA/git/govoplan-datasources/webui
|
|||||||
cd /mnt/DATA/git/govoplan-workflow/webui
|
cd /mnt/DATA/git/govoplan-workflow/webui
|
||||||
"$NPM" run typecheck
|
"$NPM" run typecheck
|
||||||
|
|
||||||
|
cd /mnt/DATA/git/govoplan-dashboard/webui
|
||||||
|
"$NPM" run test:dashboard-layout
|
||||||
|
|
||||||
|
cd /mnt/DATA/git/govoplan-postbox/webui
|
||||||
|
"$NPM" run test:ui-structure
|
||||||
|
|
||||||
cd /mnt/DATA/git/govoplan-mail/webui
|
cd /mnt/DATA/git/govoplan-mail/webui
|
||||||
"$NPM" run test:mail-ui
|
"$NPM" run test:mail-ui
|
||||||
|
|
||||||
|
|||||||
@@ -496,7 +496,12 @@ run_bandit() {
|
|||||||
fi
|
fi
|
||||||
if [[ "${#PY_TEST_ROOTS[@]}" -gt 0 ]]; then
|
if [[ "${#PY_TEST_ROOTS[@]}" -gt 0 ]]; then
|
||||||
prepare_machine_report "$REPORTS_DIR/bandit-tests.json" || return 2
|
prepare_machine_report "$REPORTS_DIR/bandit-tests.json" || return 2
|
||||||
bandit -r "${PY_TEST_ROOTS[@]}" -f json -o "$REPORTS_DIR/bandit-tests.json"
|
# Tests intentionally use assertions and synthetic credentials. Keep the
|
||||||
|
# separate test scan useful by excluding only those test-specific signals.
|
||||||
|
bandit -r "${PY_TEST_ROOTS[@]}" \
|
||||||
|
--skip B101,B105,B106,B107 \
|
||||||
|
-f json \
|
||||||
|
-o "$REPORTS_DIR/bandit-tests.json"
|
||||||
local test_status=$?
|
local test_status=$?
|
||||||
[[ "$test_status" -le 1 ]] || status=2
|
[[ "$test_status" -le 1 ]] || status=2
|
||||||
fi
|
fi
|
||||||
@@ -512,7 +517,11 @@ run_ruff_security() {
|
|||||||
fi
|
fi
|
||||||
if [[ "${#PY_TEST_ROOTS[@]}" -gt 0 ]]; then
|
if [[ "${#PY_TEST_ROOTS[@]}" -gt 0 ]]; then
|
||||||
prepare_machine_report "$REPORTS_DIR/ruff-security-tests.json" || return 2
|
prepare_machine_report "$REPORTS_DIR/ruff-security-tests.json" || return 2
|
||||||
ruff check --select S --output-format json "${PY_TEST_ROOTS[@]}" > "$REPORTS_DIR/ruff-security-tests.json"
|
ruff check \
|
||||||
|
--select S \
|
||||||
|
--ignore S101,S105,S106,S107 \
|
||||||
|
--output-format json \
|
||||||
|
"${PY_TEST_ROOTS[@]}" > "$REPORTS_DIR/ruff-security-tests.json"
|
||||||
local test_status=$?
|
local test_status=$?
|
||||||
[[ "$test_status" -le 1 ]] || status=2
|
[[ "$test_status" -le 1 ]] || status=2
|
||||||
fi
|
fi
|
||||||
@@ -582,14 +591,32 @@ run_trivy() {
|
|||||||
run_pip_audit_manifests() {
|
run_pip_audit_manifests() {
|
||||||
local status=0
|
local status=0
|
||||||
for repo in "${REPOS[@]}"; do
|
for repo in "${REPOS[@]}"; do
|
||||||
[[ -f "$repo/requirements.txt" ]] || continue
|
local repo_name
|
||||||
local name
|
repo_name="$(safe_name "$repo")"
|
||||||
name="$(safe_name "$repo")"
|
while IFS= read -r -d '' requirements_file; do
|
||||||
prepare_machine_report "$REPORTS_DIR/pip-audit-$name.json" || return 2
|
local manifest_name report_path
|
||||||
# Requirements may contain project-relative entries such as `.[server]`.
|
manifest_name="$(safe_name "$requirements_file")"
|
||||||
# Resolve them from the owning repository instead of the meta-repository.
|
report_path="$REPORTS_DIR/pip-audit-$repo_name-$manifest_name.json"
|
||||||
(cd "$repo" && pip-audit -r requirements.txt --progress-spinner off --format json --output "$REPORTS_DIR/pip-audit-$name.json")
|
prepare_machine_report "$report_path" || return 2
|
||||||
accumulate_exit_status status "$?"
|
# Requirements may contain project-relative entries such as `.[server]`.
|
||||||
|
# Resolve them from the owning repository instead of the meta-repository.
|
||||||
|
(
|
||||||
|
cd "$repo" &&
|
||||||
|
pip-audit \
|
||||||
|
-r "$(basename "$requirements_file")" \
|
||||||
|
--progress-spinner off \
|
||||||
|
--format json \
|
||||||
|
--output "$report_path"
|
||||||
|
)
|
||||||
|
accumulate_exit_status status "$?"
|
||||||
|
done < <(
|
||||||
|
find "$repo" \
|
||||||
|
-maxdepth 1 \
|
||||||
|
-type f \
|
||||||
|
-name 'requirements*.txt' \
|
||||||
|
-print0 |
|
||||||
|
sort -z
|
||||||
|
)
|
||||||
done
|
done
|
||||||
return "$status"
|
return "$status"
|
||||||
}
|
}
|
||||||
@@ -597,12 +624,38 @@ run_pip_audit_manifests() {
|
|||||||
run_npm_audit_manifests() {
|
run_npm_audit_manifests() {
|
||||||
local status=0
|
local status=0
|
||||||
for repo in "${REPOS[@]}"; do
|
for repo in "${REPOS[@]}"; do
|
||||||
[[ -f "$repo/webui/package-lock.json" ]] || continue
|
local repo_name
|
||||||
local name
|
repo_name="$(safe_name "$repo")"
|
||||||
name="$(safe_name "$repo")"
|
while IFS= read -r -d '' lock_file; do
|
||||||
prepare_machine_report "$REPORTS_DIR/npm-audit-$name.json" || return 2
|
local lock_dir lock_name runtime_report all_report
|
||||||
(cd "$repo/webui" && npm audit --omit=dev --json > "$REPORTS_DIR/npm-audit-$name.json")
|
lock_dir="$(dirname "$lock_file")"
|
||||||
accumulate_exit_status status "$?"
|
lock_name="$(
|
||||||
|
printf '%s' "${lock_file#"$repo"/}" |
|
||||||
|
tr -c 'A-Za-z0-9_.-' '_'
|
||||||
|
)"
|
||||||
|
runtime_report="$REPORTS_DIR/npm-audit-runtime-$repo_name-$lock_name.json"
|
||||||
|
all_report="$REPORTS_DIR/npm-audit-all-$repo_name-$lock_name.json"
|
||||||
|
prepare_machine_report "$runtime_report" || return 2
|
||||||
|
(
|
||||||
|
cd "$lock_dir" &&
|
||||||
|
npm audit --omit=dev --json > "$runtime_report"
|
||||||
|
)
|
||||||
|
accumulate_exit_status status "$?"
|
||||||
|
prepare_machine_report "$all_report" || return 2
|
||||||
|
(
|
||||||
|
cd "$lock_dir" &&
|
||||||
|
npm audit --json > "$all_report"
|
||||||
|
)
|
||||||
|
accumulate_exit_status status "$?"
|
||||||
|
done < <(
|
||||||
|
find "$repo" \
|
||||||
|
-maxdepth 3 \
|
||||||
|
-type f \
|
||||||
|
-name package-lock.json \
|
||||||
|
-not -path '*/node_modules/*' \
|
||||||
|
-print0 |
|
||||||
|
sort -z
|
||||||
|
)
|
||||||
done
|
done
|
||||||
return "$status"
|
return "$status"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user