Create internal API endpoint for SDRS callbacks
Description
Implement a secure internal API endpoint to receive verification results from SDRS using JWT authentication.
Acceptance Criteria
-
Create API::Internal::TokenStatus
endpoint -
Implement JWT validation for incoming requests -
Validate JWT claims (exp, iss, aud, etc.) -
Update FindingTokenStatus
with received status -
Handle all possible status values (active, revoked, error) -
Implement request correlation using jti claim -
Add rate limiting -
Log all callback attempts for audit -
Return appropriate HTTP status codes
Implementation Plan
module API
module Internal
class TokenStatus < ::API::Base
before { authenticate_sdrs_callback! }
namespace 'internal' do
desc 'Receive token status callback from SDRS'
params do
requires :finding_id, type: Integer
requires :status, type: String, values: %w[active revoked error]
optional :metadata, type: Hash
requires :checked_at, type: DateTime
end
post 'token_status/callback' do
finding = Vulnerabilities::Finding.find(params[:finding_id])
# Verify the finding matches JWT claims
jwt_claims = env['sdrs.jwt_claims']
forbidden! unless jwt_claims['gitlab']['finding_id'] == params[:finding_id]
# Update status
token_status = finding.secret_detection_token_statuses.find_or_initialize_by(
token_field: finding.token_field
)
token_status.update!(
status: params[:status],
metadata: params[:metadata],
checked_at: params[:checked_at]
)
# Log for audit
Gitlab::AppLogger.info(
message: 'SDRS callback received',
finding_id: params[:finding_id],
status: params[:status],
jti: jwt_claims['jti']
)
status 200
end
end
private
def authenticate_sdrs_callback!
token = request.headers['Authorization']&.split(' ')&.last
unauthorized! unless token
begin
payload = JWT.decode(
token,
sdrs_public_key,
true,
{
algorithm: 'RS256',
verify_iss: true,
iss: 'secret-detection-response-service',
verify_aud: true,
aud: 'gitlab-secret-detection-callback',
verify_iat: true
}
)
env['sdrs.jwt_claims'] = payload.first
rescue JWT::DecodeError => e
unauthorized!
end
end
end
end
end
Edited by Aditya Tiwari