(ctx context.Context, e *auditEntry)
| 187 | } |
| 188 | |
| 189 | func (in *AuditInterceptor) createAuditLog(ctx context.Context, e *auditEntry) error { |
| 190 | // Skip audit logging for validate-only requests. |
| 191 | if isValidateOnlyRequest(e.request) { |
| 192 | return nil |
| 193 | } |
| 194 | |
| 195 | requestString, err := getRequestString(e.request) |
| 196 | if err != nil { |
| 197 | return errors.Wrapf(err, "failed to get request string") |
| 198 | } |
| 199 | responseString, err := getResponseString(e.response) |
| 200 | if err != nil { |
| 201 | return errors.Wrapf(err, "failed to get response string") |
| 202 | } |
| 203 | |
| 204 | var user string |
| 205 | if u, ok := GetUserFromContext(ctx); ok { |
| 206 | user = common.FormatUserEmail(u.Email) |
| 207 | } else { |
| 208 | // Try to get user from successful login response. |
| 209 | if loginResponse, ok := e.response.(*v1pb.LoginResponse); ok { |
| 210 | user = loginResponse.GetUser().GetName() |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | authContextAny := ctx.Value(common.AuthContextKey) |
| 215 | authContext, ok := authContextAny.(*common.AuthContext) |
| 216 | if !ok { |
| 217 | return connect.NewError(connect.CodeInternal, errors.New("auth context not found")) |
| 218 | } |
| 219 | |
| 220 | requestMetadata := getRequestMetadataFromHeaders(e.headers, e.peerAddr) |
| 221 | |
| 222 | // Build the list of parents to audit under. Normally these come from the |
| 223 | // ACL interceptor via authContext.Resources. For audited methods that run |
| 224 | // without a workspace-bound caller (Login/Signup/ExchangeToken), Resources |
| 225 | // is empty; fall back to the workspace the handler announced, or any |
| 226 | // workspace embedded in the response, so the audit entry is still written. |
| 227 | type auditParent struct { |
| 228 | parent string |
| 229 | auditWorkspaceID string |
| 230 | } |
| 231 | var parents []auditParent |
| 232 | for _, authResource := range authContext.Resources { |
| 233 | switch authResource.Type { |
| 234 | case common.ResourceTypeProject: |
| 235 | parents = append(parents, auditParent{ |
| 236 | parent: common.FormatProject(authResource.ID), |
| 237 | }) |
| 238 | case common.ResourceTypeWorkspace: |
| 239 | parents = append(parents, auditParent{ |
| 240 | parent: common.FormatWorkspace(authResource.ID), |
| 241 | auditWorkspaceID: authResource.ID, |
| 242 | }) |
| 243 | default: |
| 244 | } |
| 245 | } |
| 246 | if len(parents) == 0 { |
no test coverage detected