ES /docs

PreprocessorService::run | end - {"stack":"HTTPError: Response code 403 (Forbidden)

RCA: PreprocessorService::run | HTTPError 403 (Forbidden) on BIM mesh download

Overview#

What Happened#

2026-04-28 16:03:28 UTC, cupixworks-deviation-preprocessor-agent 서비스에서 deviation job 1040523 처리 중 BIM 19181의 mesh 파일 다운로드 시 Tesla 내부 API로부터 403 Forbidden 응답을 받아 전체 job이 실패했다. 단건 발생이며 사용자 msullivan@sebastiancg.com (team: sebastiancg)의 세션으로 인증된 상태에서 발생했다.

Quick Facts#

Field Value
exception.class HTTPError
exception.message Response code 403 (Forbidden)
top_frame got/dist/source/core/index.js:913 (library), actual call site: BasePreprocessorRunner::downloadFile
env production, us-west-2

Timeline#

  1. 16:03:28.235Z — SQS 메시지 수신, job 1040523 처리 시작
  2. 16:03:28.294Z — 세션 인증 완료 (session_id: d871516f...)
  3. 16:03:28.500Z — deviation 9878 로드 완료, BIM mesh 다운로드 단계 진입
  4. 16:03:28.766Z — BIM 19181 mesh download에서 403 Forbidden 발생
  5. 16:03:28.767ZPreprocessorService::run 에러 전파, job 실패 처리
  6. 16:03:28.972Z — workspace 정리 완료, SQS 메시지 삭제 (재시도 없음)

Error Log#

Datadog Logs

text
PreprocessorService::run | end - {"stack":"HTTPError: Response code 403 (Forbidden)
    at Request._onResponseBase (/tmp/agent/dist/node_modules/got/dist/source/core/index.js:913:31)
    at Request._onResponse (/tmp/agent/dist/node_modules/got/dist/source/core/index.js:948:24)
    at ClientRequest.<anonymous> (/tmp/agent/dist/node_modules/got/dist/source/core/index.js:962:23)
    ...","message":"Response code 403 (Forbidden)","name":"HTTPError","code":"ERR_NON_2XX_3XX_RESPONSE"}

Impact#

  • Service: cupixworks-deviation-preprocessor-agent
  • Team: sebastiancg
  • 발생 횟수: 1
  • 최초 발생: 2026-04-28T16:03:28.767Z
  • 최근 발생: 2026-04-28T16:03:28.767Z

Root Cause Summary#

사용자 msullivan@sebastiancg.com의 세션 토큰으로 인증된 deviation preprocessor agent가 BIM 19181의 mesh 파일을 Tesla 내부 API(/api/v1/bims/19181/resources/mesh/download)에서 다운로드하려 했으나, 해당 사용자에게 이 BIM 리소스에 대한 read 권한이 없어 Pundit policy check에서 PermissionDenied (403)가 반환되었다. Agent는 SQS 메시지에 포함된 사용자 세션으로 인증하므로, 사용자의 BIM 접근 권한이 없거나 제거된 경우 이 에러가 발생한다.

Technical Analysis#

Code Path#

  • Entry point: base-service.ts:153runByMessage SQS 메시지 처리
  • Authentication: base-service.ts:194authenticateByMessage 사용자 세션 토큰으로 인증
applications/agents/packages/base/src/base-service.ts:194-201typescript
private authenticateByMessage = async (msgObject: any): Promise<void> => {
    logger.debug('BaseService::authenticateByMessage | begin');
    this.cupixAuth.setAuthParams({
        encodedAuthParams: msgObject.encoded_auth_params,
        session: msgObject.session
    });
    await this.cupixAuth.startSession();
    logger.debug('BaseService::authenticateByMessage | end');
};
  • Token construction: cupix-auth.ts:192 — 세션 정보로 _sessionToken 생성
applications/agents/packages/api/src/authentication/cupix-auth.ts:36,192typescript
get accessToken(): string | undefined { return this._sessionToken ? this._sessionToken : this.currentToken?.access_token; }
// ...
this._sessionToken = `session_token:${params.session.token},session_id:${params.session.id}`;
  • Download URL 구성: cpbim.ts:61 — BIM ID로 다운로드 URL 생성
applications/agents/packages/models/src/cpbim.ts:58-61typescript
private initialize = (): void => {
    const idStr = this.id.toString();
    this._meshArchiveFileDownloadUrl = CPX_API_ENDPOINT + '/bims/' + idStr + '/resources/mesh/download';
    // ...
};
  • Failure point: base-preprocessor-runner.ts:114got.stream.get으로 다운로드 요청
applications/agents/packages/siteinsights/src/runner/base-preprocessor-runner.ts:114-119typescript
const downloadStream = got.stream.get(downloadItem.url, {
    isStream: true,
    headers: {
        'X-CUPIX-AUTH': accessToken
    }
} as any);
  • Tesla API authorization: application_policy.rb:38-73 — Pundit read? policy에서 applied_permission 확인
app/policies/application_policy.rb:38-45ruby
def read?
  return true if user.member_of_admin_groups?(%w[administrator senior_editing_engineers])

  if record.has_attribute?(:applied_permission)
    if record.applied_permission[1] == 1 || record.applied_permission[0] == 1 || record.applied_permission[4] == 1
      true
    else
      false
    end
  end
end

기대 동작: 사용자 세션으로 BIM mesh를 다운로드할 수 있어야 함. 실제 동작: Tesla API가 해당 사용자에게 BIM 19181 리소스에 대한 read 권한이 없다고 판단하여 403 반환.

Log Evidence#

사용한 Datadog 쿼리:

text
service:cupixworks-deviation-preprocessor-agent status:error @environment:production
text
service:cupixworks-deviation-preprocessor-agent @environment:production

핵심 에러 로그 (16:03:28.766Z):

json
{
  "message": "BasePreprocessorRunner::downloadFile | error_download",
  "url": "http://api-tesla.cupix.internal/api/v1/bims/19181/resources/mesh/download",
  "path": "/tmp/workspace/9878/input_data/bim_model/19181/mesh.zip",
  "error": "HTTPError: Response code 403 (Forbidden)",
  "code": "ERR_NON_2XX_3XX_RESPONSE"
}

컨텍스트 속성:

json
{
  "job.id": 1040523,
  "deviation.id": 9878,
  "bim.id": 19181,
  "team.id": 1184,
  "team.domain": "sebastiancg",
  "user.id": 45497,
  "user.email": "msullivan@sebastiancg.com",
  "session.id": "d871516f2f950c57a54e5ee826b17d86d5071d27"
}

타임라인 핵심 포인트:

  • 16:03:28.294Z — 세션 인증 성공 (세션 자체는 유효)
  • 16:03:28.537Z — deviation 9878 조회 성공 (deviation 접근 권한 있음)
  • 16:03:28.766Z — BIM 19181 mesh download 실패 (BIM 리소스 접근 권한 없음)

이 패턴은 deviation에 연결된 BIM이 사용자가 접근할 수 없는 workspace/facility에 속하거나, 해당 BIM의 review 또는 facility-level 권한이 제거된 경우에 발생한다.

Hypotheses Considered#

# Hypothesis Evidence for Evidence against Verdict
H1 사용자에게 BIM 19181에 대한 read 권한 부족 (Pundit policy applied_permission 미충족) 세션 인증 성공 (16:03:28.294Z), deviation 조회 성공 (16:03:28.537Z), but BIM download만 403. Tesla API는 Pundit.policy(current_user, model).read? false 시 403 반환. Confirmed
H2 세션 토큰 만료 또는 무효 CupixAuth::setSession 로그에서 세션 성공, deviation API 호출도 성공. 토큰 만료였다면 모든 API 호출이 실패했을 것. Rejected
H3 BIM 19181 리소스(mesh)가 존재하지 않아 404 반환 응답 코드가 403이지 404가 아님. Tesla는 리소스 미존재 시 revision == 0 체크로 404를 반환함. Rejected
H4 Agent가 X-CUPIX-AUTH 헤더를 잘못 설정 downloadFile에서 accessToken을 직접 전달 (base-preprocessor-runner.ts:117) accessToken getter가 유효한 _sessionToken을 반환함 (세션 인증 성공으로 확인). 다른 API 호출은 정상 동작. Rejected

Fix Recommendation#

즉시 조치 (Critical)#

  • 데이터 확인: BIM 19181이 사용자 45497 (team 1184)가 접근 가능한 facility/workspace에 속하는지 Tesla DB에서 확인 필요.
  • 이 에러는 사용자 권한 문제로, agent 코드 버그가 아닌 데이터/권한 설정 이슈일 가능성이 높다. 사용자에게 BIM 접근 권한을 부여하면 즉시 해결될 수 있다.

단기 개선 (1주 이내)#

  • DeviationReportRunner::downloadFiles에서 403 에러 발생 시 어떤 BIM/리소스가 권한 부족인지 명확한 에러 메시지를 로깅하도록 개선. 현재는 generic error_download 로그만 남겨 디버깅이 어렵다.
  • preprocessor-service.ts:93-96의 catch 블록에서 403 에러를 별도 처리하여 warn 레벨로 "permission denied for BIM {id}" 메시지를 남기고, updateErrorActionJob 시 구체적인 에러 코드를 전달하는 방향 검토.

장기 개선 (재발 방지)#

  • Deviation 생성/큐잉 시점에 참조된 모든 BIM 리소스에 대한 사용자 권한을 사전 검증(pre-flight check)하여, 권한 없는 리소스가 포함된 job이 agent까지 도달하지 않도록 방지.
  • Agent에서 사용자 세션 대신 시스템 서비스 계정(admin token)으로 파일 다운로드를 수행하는 아키텍처 검토. 현재 사용자 세션 기반 인증은 사용자 권한 변동에 취약하다.

Monitoring#

  • 추가할 메트릭: BIM download 403 발생 빈도 by team/user
  • Datadog 쿼리:
text
service:cupixworks-deviation-preprocessor-agent "error_download" "403"
  • 동일 패턴 반복 시 특정 team/user의 권한 설정 문제를 사전 탐지 가능.

Risk Assessment#

  • Risk level: low
  • 예상 복잡도: trivial
  • 단건 발생이며 특정 사용자의 권한 이슈로 판단. 시스템 전반에 영향을 주는 버그가 아니라 데이터/권한 설정 문제.