diff --git a/fogwall-dashboard/frontend/src/pages/PushDetail.tsx b/fogwall-dashboard/frontend/src/pages/PushDetail.tsx
index 71e73a69..816e4798 100644
--- a/fogwall-dashboard/frontend/src/pages/PushDetail.tsx
+++ b/fogwall-dashboard/frontend/src/pages/PushDetail.tsx
@@ -5,7 +5,14 @@ import { ColorSchemeType } from 'diff2html/lib/types'
import 'diff2html/bundles/css/diff2html.min.css'
import { approvePush, cancelPush, fetchDiff, fetchProviders, fetchPush, rejectPush } from '../api'
import { StatusBadge } from '../components/StatusBadge'
-import type { AttestationQuestion, CurrentUser, Provider, PushRecord, Step } from '../types'
+import type {
+ AttestationLink,
+ AttestationQuestion,
+ CurrentUser,
+ Provider,
+ PushRecord,
+ Step,
+} from '../types'
// Steps that are infrastructure/pre-processing, not user-visible validation checks
const NON_VALIDATION_STEPS = new Set([
@@ -271,18 +278,37 @@ function AttestationQuestionField({
)
+ const linksEl = question.links && question.links.length > 0 && (
+
+ )
+
if (question.type === 'checkbox') {
return (
-
+
+
+ {linksEl}
+
)
}
@@ -303,6 +329,7 @@ function AttestationQuestionField({
))}
+ {linksEl}
)
}
@@ -315,9 +342,10 @@ function AttestationQuestionField({
value={value}
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
- placeholder={question.tooltip ?? ''}
+ placeholder=""
className="border border-gray-300 rounded px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-300 disabled:bg-gray-50 disabled:text-gray-400 dark:bg-slate-700 dark:border-slate-600 dark:text-gray-200 dark:disabled:bg-gray-800 dark:disabled:text-gray-500"
/>
+ {linksEl}
)
}
diff --git a/fogwall-dashboard/frontend/src/types.ts b/fogwall-dashboard/frontend/src/types.ts
index 137570b3..2fcc8f99 100644
--- a/fogwall-dashboard/frontend/src/types.ts
+++ b/fogwall-dashboard/frontend/src/types.ts
@@ -22,13 +22,18 @@ export interface Commit {
signedOffBy?: string[]
}
+export interface AttestationLink {
+ text: string
+ url: string
+}
+
export interface AttestationQuestion {
id: string
type: 'checkbox' | 'text' | 'dropdown'
label: string
required: boolean
options?: string[]
- tooltip?: string
+ links?: AttestationLink[]
}
export interface Attestation {
diff --git a/fogwall-server/src/main/java/com/rbc/fogwall/config/AttestationQuestion.java b/fogwall-server/src/main/java/com/rbc/fogwall/config/AttestationQuestion.java
index 6c8a165a..47748c9b 100644
--- a/fogwall-server/src/main/java/com/rbc/fogwall/config/AttestationQuestion.java
+++ b/fogwall-server/src/main/java/com/rbc/fogwall/config/AttestationQuestion.java
@@ -23,6 +23,13 @@ public class AttestationQuestion {
/** Options for {@code dropdown} type questions. Ignored for other types. */
private List options = new ArrayList<>();
- /** Optional tooltip / help text shown alongside the question. */
- private String tooltip;
+ /** Optional policy or reference links rendered below the question label. */
+ private List links = new ArrayList<>();
+
+ /** A labelled URL rendered as an anchor below an attestation question. */
+ @Data
+ public static class AttestationLink {
+ private String text;
+ private String url;
+ }
}
diff --git a/test/gitea-push-fail.sh b/test/gitea-push-fail.sh
new file mode 100755
index 00000000..0dc3dab1
--- /dev/null
+++ b/test/gitea-push-fail.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# Failure-path store-and-forward push to local Gitea via fogwall.
+# Verifies secret scanning correctly rejects a commit containing an AWS key.
+# Requires: docker compose stack up + docker/gitea-setup.sh already run.
+set -euo pipefail
+
+source "$(dirname "${BASH_SOURCE[0]}")/env.sh"
+source "$(dirname "${BASH_SOURCE[0]}")/gitea/tokens.env"
+
+GITEA_HOST="${GITEA_HOST:-localhost:3000}"
+GIT_USERNAME="${GIT_USERNAME:-me}"
+GIT_PASSWORD="${GITEA_TESTUSER_TOKEN}"
+PUSH_URL="http://${GIT_USERNAME}:${GIT_PASSWORD}@localhost:8080/push/${GITEA_HOST}/test-owner/test-repo.git"
+TEST_BRANCH="test/gitea-fail-$(date +%s)"
+REPO_DIR=$(mktemp -d "${_SYS_TMPDIR}/gitea-push-fail-XXXX")
+
+cleanup() {
+ git -C "${REPO_DIR}" remote set-url origin "http://${GIT_USERNAME}:${GIT_PASSWORD}@${GITEA_HOST}/test-owner/test-repo.git" 2>/dev/null || true
+ git -C "${REPO_DIR}" push origin --delete "${TEST_BRANCH}" 2>/dev/null || true
+ safe_rm_rf "${REPO_DIR}"
+}
+trap cleanup EXIT
+
+git clone "${PUSH_URL}" "${REPO_DIR}"
+cd "${REPO_DIR}"
+git checkout -b "${TEST_BRANCH}"
+git config user.name "test-user"
+git config user.email "testuser@example.com"
+
+cat > aws-credentials << 'EOF'
+[default]
+aws_access_key_id = AKIAYVP4CIPPH3TESTKEY
+aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
+EOF
+git add aws-credentials
+git commit -m "chore: add deployment credentials"
+
+push_exit=0
+git push origin "${TEST_BRANCH}" 2>&1 || push_exit=$?
+
+if [[ ${push_exit} -ne 0 ]]; then
+ echo "PASSED (push correctly rejected by secret scanning)"
+else
+ echo "FAILED (push should have been rejected)"
+ exit 1
+fi
diff --git a/test/gitea-push-pass.sh b/test/gitea-push-pass.sh
new file mode 100755
index 00000000..65f2fc72
--- /dev/null
+++ b/test/gitea-push-pass.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# Golden-path store-and-forward push to local Gitea via fogwall.
+# Requires: docker compose stack up + docker/gitea-setup.sh already run.
+set -euo pipefail
+
+source "$(dirname "${BASH_SOURCE[0]}")/env.sh"
+source "$(dirname "${BASH_SOURCE[0]}")/gitea/tokens.env"
+
+GITEA_HOST="${GITEA_HOST:-localhost:3000}"
+GIT_USERNAME="${GIT_USERNAME:-me}"
+GIT_PASSWORD="${GITEA_TESTUSER_TOKEN}"
+PUSH_URL="http://${GIT_USERNAME}:${GIT_PASSWORD}@localhost:8080/push/${GITEA_HOST}/test-owner/test-repo.git"
+TEST_BRANCH="test/gitea-pass-$(date +%s)"
+REPO_DIR=$(mktemp -d "${_SYS_TMPDIR}/gitea-push-pass-XXXX")
+
+cleanup() {
+ git -C "${REPO_DIR}" remote set-url origin "http://${GIT_USERNAME}:${GIT_PASSWORD}@${GITEA_HOST}/test-owner/test-repo.git" 2>/dev/null || true
+ git -C "${REPO_DIR}" push origin --delete "${TEST_BRANCH}" 2>/dev/null || true
+ safe_rm_rf "${REPO_DIR}"
+}
+trap cleanup EXIT
+
+git clone "${PUSH_URL}" "${REPO_DIR}"
+cd "${REPO_DIR}"
+git checkout -b "${TEST_BRANCH}"
+git config user.name "test-user"
+git config user.email "testuser@example.com"
+
+echo "pass - $(date)" >> test-file.txt
+git add test-file.txt
+git commit -m "feat: golden-path gitea store-and-forward test"
+git push origin "${TEST_BRANCH}"
+
+echo "PASSED"