From 3aba59697540ae3dc7a230b42508d3dc5f8f13a1 Mon Sep 17 00:00:00 2001 From: ReiDo Date: Fri, 15 May 2026 11:15:08 +0900 Subject: [PATCH 1/3] Remove console Slack webhook from source control The console app still committed a Slack incoming webhook while related common-app credential hardening is already covered by separate open PRs. This keeps the fix limited to console config, documents the runtime variables, and adds a static guard for regression checks. Constraint: Bounty scope needs to avoid overlapping existing S3, service-token, Cloudinary, and third-party credential PRs Rejected: Touch common/config/main.php | already covered by open third-party credential PRs Confidence: medium Scope-risk: narrow Directive: Keep this PR scoped to console Slack config unless the existing broader third-party credential PR is closed without merge Tested: python scripts/check-console-slack-hardening.py; python -m py_compile scripts/check-console-slack-hardening.py; git diff --check Not-tested: php -l console/config/main.php because php is not installed locally --- console/config/main.php | 7 ++++- docs/console-slack-env.md | 18 ++++++++++++ scripts/check-console-slack-hardening.py | 36 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 docs/console-slack-env.md create mode 100644 scripts/check-console-slack-hardening.py diff --git a/console/config/main.php b/console/config/main.php index 1370df98..91c93bd4 100644 --- a/console/config/main.php +++ b/console/config/main.php @@ -6,6 +6,11 @@ require(__DIR__ . '/params-local.php') ); +$consoleSlackWebhookUrl = getenv('CONSOLE_SLACK_WEBHOOK_URL'); +if (!$consoleSlackWebhookUrl) { + $consoleSlackWebhookUrl = getenv('SLACK_WEBHOOK_URL') ?: ''; +} + return [ 'id' => 'app-console', 'basePath' => dirname(__DIR__), @@ -26,7 +31,7 @@ 'slack' => [ 'class' => 'understeam\slack\Client', - 'url' => 'https://hooks.slack.com/services/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', + 'url' => $consoleSlackWebhookUrl, 'username' => 'StudentHub', ], 'log' => [ diff --git a/docs/console-slack-env.md b/docs/console-slack-env.md new file mode 100644 index 00000000..419ef739 --- /dev/null +++ b/docs/console-slack-env.md @@ -0,0 +1,18 @@ +# Console Slack Webhook Configuration + +The console app reads Slack webhook URLs from runtime environment variables instead of storing a webhook in `console/config/main.php`. + +## Variables + +- `CONSOLE_SLACK_WEBHOOK_URL`: Optional console-specific Slack incoming webhook URL. +- `SLACK_WEBHOOK_URL`: Shared fallback webhook URL used when `CONSOLE_SLACK_WEBHOOK_URL` is not set. + +Store these values in the deployment secret manager or in local environment files that are excluded from source control. Do not commit full Slack webhook URLs. + +## Regression Check + +Run the console Slack hardening check before opening config changes: + +```bash +python scripts/check-console-slack-hardening.py +``` diff --git a/scripts/check-console-slack-hardening.py b/scripts/check-console-slack-hardening.py new file mode 100644 index 00000000..1d2fb0e0 --- /dev/null +++ b/scripts/check-console-slack-hardening.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +CONSOLE_CONFIG = ROOT / "console" / "config" / "main.php" + + +def main() -> int: + text = CONSOLE_CONFIG.read_text(encoding="utf-8") + failures = [] + + if "hooks.slack.com/services" in text: + failures.append("console/config/main.php still contains a Slack webhook URL") + + if "CONSOLE_SLACK_WEBHOOK_URL" not in text: + failures.append("console/config/main.php does not read CONSOLE_SLACK_WEBHOOK_URL") + + if "SLACK_WEBHOOK_URL" not in text: + failures.append("console/config/main.php does not include the shared SLACK_WEBHOOK_URL fallback") + + if "'url' => $consoleSlackWebhookUrl" not in text: + failures.append("console/config/main.php does not wire the Slack client URL through the env-backed value") + + if failures: + print("Console Slack webhook hardening check failed:") + for failure in failures: + print(f"- {failure}") + return 1 + + print("Console Slack webhook hardening check passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 6f068544661babca20fcf3caec1bebeeac5481a2 Mon Sep 17 00:00:00 2001 From: ReiDo Date: Fri, 15 May 2026 11:44:55 +0900 Subject: [PATCH 2/3] Address console Slack checker review warning CodeRabbit flagged docstring coverage on the small regression checker. Adding module and function docstrings keeps the PR quality signal clean without changing behavior. Constraint: Keep the update limited to the checker script Confidence: high Scope-risk: narrow Tested: python scripts/check-console-slack-hardening.py; python -m py_compile scripts/check-console-slack-hardening.py; git diff --check --- scripts/check-console-slack-hardening.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/check-console-slack-hardening.py b/scripts/check-console-slack-hardening.py index 1d2fb0e0..c1cebb8e 100644 --- a/scripts/check-console-slack-hardening.py +++ b/scripts/check-console-slack-hardening.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +"""Validate that console Slack webhook config stays environment-backed.""" + from pathlib import Path @@ -7,6 +9,8 @@ def main() -> int: + """Return a non-zero exit code when console Slack hardening regresses.""" + text = CONSOLE_CONFIG.read_text(encoding="utf-8") failures = [] From 8a88298983aa32f98db18ffb9491e607cc41ad9c Mon Sep 17 00:00:00 2001 From: ReiDo Date: Fri, 15 May 2026 11:50:13 +0900 Subject: [PATCH 3/3] Make console Slack checker formatting tolerant CodeRabbit noted that the checker depended on exact PHP spacing. Switching the URL wiring check to a small regex keeps the guard focused on behavior instead of formatting. Constraint: Preserve the existing checker scope and avoid changing runtime PHP behavior Confidence: high Scope-risk: narrow Tested: python scripts/check-console-slack-hardening.py; python -m py_compile scripts/check-console-slack-hardening.py; git diff --check --- scripts/check-console-slack-hardening.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/check-console-slack-hardening.py b/scripts/check-console-slack-hardening.py index c1cebb8e..8ce69d38 100644 --- a/scripts/check-console-slack-hardening.py +++ b/scripts/check-console-slack-hardening.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Validate that console Slack webhook config stays environment-backed.""" +import re from pathlib import Path @@ -23,7 +24,7 @@ def main() -> int: if "SLACK_WEBHOOK_URL" not in text: failures.append("console/config/main.php does not include the shared SLACK_WEBHOOK_URL fallback") - if "'url' => $consoleSlackWebhookUrl" not in text: + if not re.search(r"['\"]url['\"]\s*=>\s*\$consoleSlackWebhookUrl\b", text): failures.append("console/config/main.php does not wire the Slack client URL through the env-backed value") if failures: