Skip to content

infra: prod 박스 관측 배선 스크립트 추가#3

Merged
m-a-king merged 1 commit into
mainfrom
infra/observability-wiring
Jul 14, 2026
Merged

infra: prod 박스 관측 배선 스크립트 추가#3
m-a-king merged 1 commit into
mainfrom
infra/observability-wiring

Conversation

@m-a-king

@m-a-king m-a-king commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Situation

extractor prod 박스(EC2)에는 지금 수집기가 없어 메트릭을 core 박스 Alloy 가 크로스박스로 긁어가고 있다. 이를 "박스마다 Alloy" 구조로 바꾸려 한다. 또한 앱 컨테이너(piki-extractor)는 지금까지 임시(수동 SSM)로 기동돼 run 파라미터가 repo 어디에도 없다.

Task

  • extractor 박스에서 공통 Alloy 블록(TeamPiKi/infra)을 호출해 관측을 배선하는 스크립트를 추가한다.
  • 앱 컨테이너 (재)기동을 SSOT 화하고, 그 김에 관측 label opt-in 과 트레이스 export env 를 신설 배선한다.

Action

  • infra/scripts/provision-observability.sh: TeamPiKi/infra 의 공통 Alloy 블록(blocks/alloy/config.alloy, provision-alloy.sh)을 fetch 하고, Grafana Cloud 자격(metrics/logs/token 필수 5종, traces 선택 2종)을 SSM Parameter Store 에서 조회해 env 로 얹은 뒤 extractor 값(environment=prod, box=piki-extractor)으로 공통 블록을 호출한다. --ref 로 infra PR 머지 전 브랜치 선검증 가능.
  • infra/scripts/run-extractor.sh: GEMINI_API_KEY 를 SSM 에서 조회해 앱 컨테이너를 재기동한다. 관측 label opt-in 4종(piki.observe/piki.service/piki.metrics.port/piki.metrics.path)과 트레이스 export env(TRACING_OTLP_ENABLED, OTLP_ENDPOINT), 구조화 로깅 env(LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs)를 신설 배선하고, 공통 healthcheck 블록으로 기동 완료를 확인한다.
  • README.md: "운영 (prod 박스)" 섹션 추가.
  • 앱 코드 변경 없음 - TRACING_OTLP_ENABLED/OTLP_ENDPOINT env 배선은 application.yml 에 이미 존재.

Result

  • bash -n 두 스크립트 통과.
  • 인자 오류 경로 확인: run-extractor.sh 인자 없이 → exit 2, 알 수 없는 인자 → exit 2. provision-observability.sh 알 수 없는 인자 → exit 2.
  • 로컬에 AWS/박스 접근이 없어 SSM·docker run·공통 블록 fetch 가 실제로 도는 성공 경로는 실행하지 않았다 - 박스 적용 단계에서 별도 실측 예정.

의존성: TeamPiKi/infra 의 공통 Alloy 블록(blocks/alloy/config.alloy, provision-alloy.sh) PR 이 아직 main 에 없다. 그 PR 이 머지된 후 provision-observability.sh 를 적용할 수 있다(머지 전에는 --ref 로 그 PR 의 브랜치를 지정해 선검증 가능).

Summary by CodeRabbit

  • New Features

    • Added production deployment guidance for running the extractor service.
    • Added a standardized script for starting or restarting the extractor container.
    • Added automated health checks after deployment.
    • Added centralized observability setup for metrics, logs, and optional traces.
    • Added secure retrieval of application and monitoring credentials from AWS Parameter Store.
  • Documentation

    • Documented production operations, remote execution, secret management, and observability configuration.

- infra/scripts/provision-observability.sh: TeamPiKi/infra 공통 Alloy 블록을
  fetch 하고, Grafana Cloud 자격을 SSM Parameter Store 에서 읽어 extractor 값
  (environment=prod, box=piki-extractor)으로 공통 블록을 호출한다. --ref 로
  infra PR 머지 전 브랜치 선검증 가능.
- infra/scripts/run-extractor.sh: 지금까지 임시(수동 SSM)로 기동되던 앱
  컨테이너의 run 파라미터를 이 스크립트 한 곳으로 흡수한다 - docker label
  opt-in(관측 대상 선언)과 트레이스 export env 를 신설 배선한다.
- README.md: 운영(prod 박스) 섹션 추가 - terraform/기동/관측 스크립트 좌표 안내.

앱 코드 변경 없음 - TRACING_OTLP_ENABLED/OTLP_ENDPOINT env 배선은
application.yml 에 이미 있다.
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

프로덕션 박스에서 Extractor 컨테이너를 SSM 시크릿과 함께 재기동하고 헬스체크하는 스크립트가 추가되었다. Grafana Alloy 설정 프로비저닝과 관련 운영 절차도 문서화되었다.

Changes

프로덕션 운영 자동화

Layer / File(s) Summary
Extractor 컨테이너 실행 및 헬스체크
infra/scripts/run-extractor.sh
이미지를 인자로 받아 SSM에서 GEMINI_API_KEY를 조회하고, 관측 환경변수·라벨을 포함한 컨테이너를 재기동한 뒤 actuator 헬스체크를 수행한다.
Alloy 관측 설정 프로비저닝
infra/scripts/provision-observability.sh
지정된 인프라 ref에서 Alloy 설정을 내려받고, Grafana 관련 SSM 파라미터를 주입해 piki-extractor용 공유 프로비저닝 스크립트를 실행한다.
프로덕션 운영 경로 문서화
README.md
EC2, SSM, 시크릿, 관측 계약 및 운영 스크립트의 프로덕션 사용 경로를 추가한다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

Extractor 실행 및 헬스체크

sequenceDiagram
  participant Operator
  participant run-extractor.sh
  participant AWS SSM
  participant Docker
  participant healthcheck.sh
  Operator->>run-extractor.sh: --image 전달
  run-extractor.sh->>AWS SSM: GEMINI_API_KEY 조회
  AWS SSM-->>run-extractor.sh: 복호화된 시크릿 반환
  run-extractor.sh->>Docker: piki-extractor 재기동
  run-extractor.sh->>healthcheck.sh: actuator health 검사
  healthcheck.sh-->>Operator: 검사 결과 반환
Loading

Alloy 관측 설정 프로비저닝

sequenceDiagram
  participant Operator
  participant provision-observability.sh
  participant GitHub
  participant AWS SSM
  participant provision-alloy.sh
  Operator->>provision-observability.sh: --ref 실행
  provision-observability.sh->>GitHub: Alloy 파일 다운로드
  provision-observability.sh->>AWS SSM: Grafana 파라미터 조회
  AWS SSM-->>provision-observability.sh: 관측 설정 반환
  provision-observability.sh->>provision-alloy.sh: prod 및 piki-extractor 설정 전달
  provision-alloy.sh-->>Operator: Alloy 설정 적용
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 prod 박스 관측 배선 스크립트 추가라는 핵심 변경을 정확히 요약합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch infra/observability-wiring

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
infra/scripts/run-extractor.sh (2)

36-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the amazon/aws-cli image tag.

No tag is specified, so this resolves to amazon/aws-cli:latest, which can change unexpectedly between prod runs (e.g. incompatible CLI flags, breaking output changes) since this is invoked repeatedly over time without any build/lock step.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/run-extractor.sh` around lines 36 - 42, Pin the Docker image
used by the `docker run` command to a specific `amazon/aws-cli` version tag
instead of relying on the mutable `latest` default. Keep the existing AWS SSM
arguments and command behavior unchanged.

45-91: 🩺 Stability & Availability | 🔵 Trivial

No rollback path if the new container fails health check, and no explicit pull before run.

The old container is force-removed (line 46) before the new one is confirmed healthy (lines 82-91). If the new image fails to start or fails the healthcheck, the script exits 1 leaving the box with either no running container or an unhealthy one — there's no fallback to the previously-working container. Also, docker run doesn't docker pull "$IMAGE" first, so if $IMAGE uses a mutable tag (e.g. :latest) that was already pulled once, the script may silently restart the old cached image instead of a newly-pushed one.

Given the fixed -p 8090:8090 binding, true blue/green isn't trivial here, but consider at minimum: (1) an explicit docker pull "$IMAGE" before removing the old container so pull failures are caught before service is torn down, and (2) capturing enough context (e.g. previous image ID) to make manual rollback faster if the healthcheck fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/run-extractor.sh` around lines 45 - 91, Update the deployment
flow around the piki-extractor container lifecycle to explicitly pull "$IMAGE"
before removing the existing container, so pull failures leave the running
service untouched. Before docker rm, capture the current container/image context
when available, and when the subsequent healthcheck fails, report that context
clearly to support restoring the previous image or container; preserve the
existing healthcheck and failure exit behavior.
infra/scripts/provision-observability.sh (2)

51-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated dockerized-aws-cli SSM helper across both scripts; unpinned amazon/aws-cli tag.

get_ssm_param() here re-implements the same docker run --rm --network host -e AWS_DEFAULT_REGION=... amazon/aws-cli ssm get-parameter ... pattern that run-extractor.sh inlines separately (lines 36-42 there). Consider extracting a shared helper (e.g. infra/scripts/lib/ssm.sh) sourced by both scripts, and pinning the amazon/aws-cli image to a specific tag instead of implicit latest for reproducibility.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/provision-observability.sh` around lines 51 - 60, Extract the
duplicated AWS SSM Docker invocation from get_ssm_param and run-extractor.sh
into a shared sourced helper such as lib/ssm.sh, preserving the existing
parameter and decryption behavior. Update both scripts to use that helper, and
replace the unpinned amazon/aws-cli image reference with one specific,
consistently used version tag.

62-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Five near-identical SSM fetch blocks — candidate for a loop.

The required-params section repeats the same fetch/error pattern five times. A small map+loop reduces duplication and the risk of a copy-paste error (e.g. mismatched param name vs. error message) creeping in on the next edit.

♻️ Proposed refactor
-GRAFANA_METRICS_URL=$(get_ssm_param /piki-extractor/grafana-metrics-url) \
-  || { echo "필수 SSM 파라미터 조회 실패: /piki-extractor/grafana-metrics-url" >&2; exit 1; }
-GRAFANA_METRICS_USER=$(get_ssm_param /piki-extractor/grafana-metrics-user) \
-  || { echo "필수 SSM 파라미터 조회 실패: /piki-extractor/grafana-metrics-user" >&2; exit 1; }
-GRAFANA_LOGS_URL=$(get_ssm_param /piki-extractor/grafana-logs-url) \
-  || { echo "필수 SSM 파라미터 조회 실패: /piki-extractor/grafana-logs-url" >&2; exit 1; }
-GRAFANA_LOGS_USER=$(get_ssm_param /piki-extractor/grafana-logs-user) \
-  || { echo "필수 SSM 파라미터 조회 실패: /piki-extractor/grafana-logs-user" >&2; exit 1; }
-GRAFANA_CLOUD_TOKEN=$(get_ssm_param /piki-extractor/grafana-cloud-token) \
-  || { echo "필수 SSM 파라미터 조회 실패: /piki-extractor/grafana-cloud-token" >&2; exit 1; }
+declare -A REQUIRED_PARAMS=(
+  [GRAFANA_METRICS_URL]=/piki-extractor/grafana-metrics-url
+  [GRAFANA_METRICS_USER]=/piki-extractor/grafana-metrics-user
+  [GRAFANA_LOGS_URL]=/piki-extractor/grafana-logs-url
+  [GRAFANA_LOGS_USER]=/piki-extractor/grafana-logs-user
+  [GRAFANA_CLOUD_TOKEN]=/piki-extractor/grafana-cloud-token
+)
+for var in "${!REQUIRED_PARAMS[@]}"; do
+  value=$(get_ssm_param "${REQUIRED_PARAMS[$var]}") \
+    || { echo "필수 SSM 파라미터 조회 실패: ${REQUIRED_PARAMS[$var]}" >&2; exit 1; }
+  export "$var=$value"
+done
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/provision-observability.sh` around lines 62 - 73, Refactor the
required-parameter fetch section into a small mapping and loop that associates
each Grafana variable with its SSM parameter path, while preserving the existing
immediate failure behavior and error message context. Replace the five
duplicated assignments for GRAFANA_METRICS_URL, GRAFANA_METRICS_USER,
GRAFANA_LOGS_URL, GRAFANA_LOGS_USER, and GRAFANA_CLOUD_TOKEN without changing
their resulting environment values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infra/scripts/provision-observability.sh`:
- Around line 29-34: Update the argument parser’s --ref branch in the while loop
to validate that a following value exists before assigning REF and shifting two
arguments. When the value is missing, exit through the existing argument-error
path so the intended “인자 오류” message is emitted instead of letting shift fail.
- Around line 44-47: Update the default ref configuration used by
provision-observability.sh and run-extractor.sh so fetched observability scripts
resolve to a tagged release or commit SHA instead of main. Preserve the existing
--ref override behavior, and ensure config.alloy, provision-alloy.sh, and
blocks/healthcheck.sh continue using the selected ref.

In `@infra/scripts/run-extractor.sh`:
- Around line 25-30: Update the --image branch in the argument-parsing loop to
validate that a following value exists before assigning IMAGE and shifting two
arguments. When --image is the final token, emit the script’s documented
argument-error usage message and exit cleanly instead of invoking shift 2 with
insufficient parameters; preserve existing handling for valid values and unknown
arguments.
- Around line 48-60: Remove the inline GEMINI_API_KEY assignment from the docker
run command in run-extractor.sh. Create a temporary environment file with
restricted permissions, write the key there, pass it using Docker’s env-file
option, and ensure the file is cleaned up after the container starts while
preserving the existing container configuration.
- Around line 82-85: Update the healthcheck download flow in run-extractor.sh
around HEALTHCHECK_SH to pin the fetched healthcheck.sh to a trusted immutable
ref or validate it with a checksum/signature, following the existing approach in
provision-observability.sh; ensure the script is only executed after that pin or
verification succeeds.

---

Nitpick comments:
In `@infra/scripts/provision-observability.sh`:
- Around line 51-60: Extract the duplicated AWS SSM Docker invocation from
get_ssm_param and run-extractor.sh into a shared sourced helper such as
lib/ssm.sh, preserving the existing parameter and decryption behavior. Update
both scripts to use that helper, and replace the unpinned amazon/aws-cli image
reference with one specific, consistently used version tag.
- Around line 62-73: Refactor the required-parameter fetch section into a small
mapping and loop that associates each Grafana variable with its SSM parameter
path, while preserving the existing immediate failure behavior and error message
context. Replace the five duplicated assignments for GRAFANA_METRICS_URL,
GRAFANA_METRICS_USER, GRAFANA_LOGS_URL, GRAFANA_LOGS_USER, and
GRAFANA_CLOUD_TOKEN without changing their resulting environment values.

In `@infra/scripts/run-extractor.sh`:
- Around line 36-42: Pin the Docker image used by the `docker run` command to a
specific `amazon/aws-cli` version tag instead of relying on the mutable `latest`
default. Keep the existing AWS SSM arguments and command behavior unchanged.
- Around line 45-91: Update the deployment flow around the piki-extractor
container lifecycle to explicitly pull "$IMAGE" before removing the existing
container, so pull failures leave the running service untouched. Before docker
rm, capture the current container/image context when available, and when the
subsequent healthcheck fails, report that context clearly to support restoring
the previous image or container; preserve the existing healthcheck and failure
exit behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cf799076-6ece-4b08-99bd-5b57d6aab9a6

📥 Commits

Reviewing files that changed from the base of the PR and between 5a08bd4 and 05dbb4c.

📒 Files selected for processing (3)
  • README.md
  • infra/scripts/provision-observability.sh
  • infra/scripts/run-extractor.sh

Comment on lines +29 to +34
while [ $# -gt 0 ]; do
case "$1" in
--ref) REF="${2:-}"; shift 2;;
*) echo "unknown arg: $1" >&2; exit 2;;
esac
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Same missing-value edge case as run-extractor.sh's --image parsing.

If --ref is passed with no following value, shift 2 on a single remaining positional param fails under set -e, crashing before the [ -n "$REF" ] check at line 36 can produce the intended "인자 오류" message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/provision-observability.sh` around lines 29 - 34, Update the
argument parser’s --ref branch in the while loop to validate that a following
value exists before assigning REF and shifting two arguments. When the value is
missing, exit through the existing argument-error path so the intended “인자 오류”
message is emitted instead of letting shift fail.

Comment on lines +44 to +47
curl -fsSL "$INFRA_RAW_BASE/config.alloy" -o "$WORK_DIR/config.alloy" \
|| { echo "config.alloy fetch 실패 (ref=$REF)" >&2; exit 1; }
curl -fsSL "$INFRA_RAW_BASE/provision-alloy.sh" -o "$WORK_DIR/provision-alloy.sh" \
|| { echo "provision-alloy.sh fetch 실패 (ref=$REF)" >&2; exit 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== infra/scripts/provision-observability.sh ==\n'
wc -l infra/scripts/provision-observability.sh
sed -n '1,140p' infra/scripts/provision-observability.sh

printf '\n== Search for REF defaults and integrity checks ==\n'
rg -n --no-heading -S 'REF=|--ref|checksum|sha256|signature|gpg|cosign|main' infra/scripts

Repository: TeamPiKi/extractor

Length of output: 4591


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== infra/scripts/run-extractor.sh ==\n'
wc -l infra/scripts/run-extractor.sh
sed -n '1,220p' infra/scripts/run-extractor.sh

Repository: TeamPiKi/extractor

Length of output: 3331


Pin the fetched observability scripts instead of defaulting to main

  • infra/scripts/provision-observability.sh:27,44-47 fetches config.alloy and provision-alloy.sh from TeamPiKi/infra/main by default, then executes the fetched provision-alloy.sh directly.
  • infra/scripts/run-extractor.sh:84 does the same for blocks/healthcheck.sh.
  • Pin the default ref to a tagged release or commit SHA; keep --ref for intentional overrides.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/provision-observability.sh` around lines 44 - 47, Update the
default ref configuration used by provision-observability.sh and
run-extractor.sh so fetched observability scripts resolve to a tagged release or
commit SHA instead of main. Preserve the existing --ref override behavior, and
ensure config.alloy, provision-alloy.sh, and blocks/healthcheck.sh continue
using the selected ref.

Comment on lines +25 to +30
while [ $# -gt 0 ]; do
case "$1" in
--image) IMAGE="${2:-}"; shift 2;;
*) echo "unknown arg: $1" >&2; exit 2;;
esac
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

--image with no value crashes ambiguously instead of a clean usage error.

If --image is the last token (no value follows), shift 2 runs with only one positional param left. Under set -euo pipefail, shift's nonzero exit (n > $#) triggers immediate script exit — before reaching the --image is required check at line 32 — with a confusing failure instead of the documented "인자 오류".

🐛 Proposed fix
   case "$1" in
-    --image) IMAGE="${2:-}"; shift 2;;
+    --image)
+      [ $# -ge 2 ] || { echo "--image requires a value" >&2; exit 2; }
+      IMAGE="$2"; shift 2;;
     *) echo "unknown arg: $1" >&2; exit 2;;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while [ $# -gt 0 ]; do
case "$1" in
--image) IMAGE="${2:-}"; shift 2;;
*) echo "unknown arg: $1" >&2; exit 2;;
esac
done
while [ $# -gt 0 ]; do
case "$1" in
--image)
[ $# -ge 2 ] || { echo "--image requires a value" >&2; exit 2; }
IMAGE="$2"; shift 2;;
*) echo "unknown arg: $1" >&2; exit 2;;
esac
done
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/run-extractor.sh` around lines 25 - 30, Update the --image
branch in the argument-parsing loop to validate that a following value exists
before assigning IMAGE and shifting two arguments. When --image is the final
token, emit the script’s documented argument-error usage message and exit
cleanly instead of invoking shift 2 with insufficient parameters; preserve
existing handling for valid values and unknown arguments.

Comment on lines +48 to +60
docker run -d --name piki-extractor --restart unless-stopped \
-p 8090:8090 \
--add-host=host.docker.internal:host-gateway \
--label piki.observe=true \
--label piki.service=piki-extractor \
--label piki.metrics.port=8090 \
--label piki.metrics.path=/actuator/prometheus \
-e AWS_REGION=ap-northeast-2 \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e TRACING_OTLP_ENABLED=true \
-e OTLP_ENDPOINT=http://host.docker.internal:4318/v1/traces \
-e LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs \
"$IMAGE"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Secret leaked via process command line.

GEMINI_API_KEY is passed with -e GEMINI_API_KEY="$GEMINI_API_KEY" on the docker run invocation. This value becomes part of the docker process's argv, which is visible to any local user via ps aux / /proc/<pid>/cmdline (and shell history if run interactively) while the command executes — a classic CWE-214-style secret exposure. docker inspect will still show the resolved env either way, but avoiding argv exposure is a straightforward hardening step.

🛡️ Proposed fix using an env-file with restricted permissions
+ENV_FILE=$(mktemp)
+chmod 600 "$ENV_FILE"
+trap 'rm -f "$ENV_FILE"' EXIT
+cat > "$ENV_FILE" <<EOF
+AWS_REGION=ap-northeast-2
+GEMINI_API_KEY=$GEMINI_API_KEY
+TRACING_OTLP_ENABLED=true
+OTLP_ENDPOINT=http://host.docker.internal:4318/v1/traces
+LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs
+EOF
+
 docker run -d --name piki-extractor --restart unless-stopped \
   -p 8090:8090 \
   --add-host=host.docker.internal:host-gateway \
   --label piki.observe=true \
   --label piki.service=piki-extractor \
   --label piki.metrics.port=8090 \
   --label piki.metrics.path=/actuator/prometheus \
-  -e AWS_REGION=ap-northeast-2 \
-  -e GEMINI_API_KEY="$GEMINI_API_KEY" \
-  -e TRACING_OTLP_ENABLED=true \
-  -e OTLP_ENDPOINT=http://host.docker.internal:4318/v1/traces \
-  -e LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs \
+  --env-file "$ENV_FILE" \
   "$IMAGE"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
docker run -d --name piki-extractor --restart unless-stopped \
-p 8090:8090 \
--add-host=host.docker.internal:host-gateway \
--label piki.observe=true \
--label piki.service=piki-extractor \
--label piki.metrics.port=8090 \
--label piki.metrics.path=/actuator/prometheus \
-e AWS_REGION=ap-northeast-2 \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e TRACING_OTLP_ENABLED=true \
-e OTLP_ENDPOINT=http://host.docker.internal:4318/v1/traces \
-e LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs \
"$IMAGE"
ENV_FILE=$(mktemp)
chmod 600 "$ENV_FILE"
trap 'rm -f "$ENV_FILE"' EXIT
cat > "$ENV_FILE" <<EOF
AWS_REGION=ap-northeast-2
GEMINI_API_KEY=$GEMINI_API_KEY
TRACING_OTLP_ENABLED=true
OTLP_ENDPOINT=http://host.docker.internal:4318/v1/traces
LOGGING_STRUCTURED_FORMAT_CONSOLE=ecs
EOF
docker run -d --name piki-extractor --restart unless-stopped \
-p 8090:8090 \
--add-host=host.docker.internal:host-gateway \
--label piki.observe=true \
--label piki.service=piki-extractor \
--label piki.metrics.port=8090 \
--label piki.metrics.path=/actuator/prometheus \
--env-file "$ENV_FILE" \
"$IMAGE"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/run-extractor.sh` around lines 48 - 60, Remove the inline
GEMINI_API_KEY assignment from the docker run command in run-extractor.sh.
Create a temporary environment file with restricted permissions, write the key
there, pass it using Docker’s env-file option, and ensure the file is cleaned up
after the container starts while preserving the existing container
configuration.

Comment on lines +82 to +85
# --- 3. 헬스 대기 - 공통 healthcheck 블록을 dogfooding ---
HEALTHCHECK_SH="/tmp/piki-run-extractor-healthcheck.sh"
curl -fsSL https://raw.githubusercontent.com/TeamPiKi/infra/main/blocks/healthcheck.sh -o "$HEALTHCHECK_SH" \
|| { echo "healthcheck.sh fetch 실패" >&2; exit 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== run-extractor excerpt ==\n'
sed -n '60,120p' infra/scripts/run-extractor.sh

printf '\n== provision-observability excerpt ==\n'
sed -n '1,220p' infra/scripts/provision-observability.sh

printf '\n== search for healthcheck.sh and ref override ==\n'
rg -n "healthcheck\.sh|--ref|raw\.githubusercontent|bash .*healthcheck|HEALTHCHECK_SH" infra/scripts

Repository: TeamPiKi/extractor

Length of output: 6109


Pin the fetched healthcheck script instead of pulling main. run-extractor.sh downloads blocks/healthcheck.sh from TeamPiKi/infra/main and runs it with bash, so any change on that branch is immediately trusted on the prod extractor box. Add a --ref/commit-SHA pin or checksum/signature check like provision-observability.sh.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/scripts/run-extractor.sh` around lines 82 - 85, Update the healthcheck
download flow in run-extractor.sh around HEALTHCHECK_SH to pin the fetched
healthcheck.sh to a trusted immutable ref or validate it with a
checksum/signature, following the existing approach in
provision-observability.sh; ensure the script is only executed after that pin or
verification succeeds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant