(r Run)
| 624 | } |
| 625 | |
| 626 | func validateRunLeaseMetadata(r Run) error { |
| 627 | claimToken := strings.TrimSpace(r.ClaimToken) |
| 628 | claimTokenHash := strings.TrimSpace(r.ClaimTokenHash) |
| 629 | if claimToken != "" && claimTokenHash == "" { |
| 630 | return fmt.Errorf("%w: task_run.claim_token_hash is required when claim_token is set", ErrValidation) |
| 631 | } |
| 632 | if claimTokenHash != "" && !isCanonicalClaimTokenHash(claimTokenHash) { |
| 633 | return fmt.Errorf("%w: task_run.claim_token_hash must be a lowercase sha256 hex hash", ErrValidation) |
| 634 | } |
| 635 | if !r.LeaseUntil.IsZero() && claimTokenHash == "" { |
| 636 | return fmt.Errorf("%w: task_run.claim_token_hash is required when lease_until is set", ErrValidation) |
| 637 | } |
| 638 | if !r.HeartbeatAt.IsZero() && claimTokenHash == "" { |
| 639 | return fmt.Errorf("%w: task_run.claim_token_hash is required when heartbeat_at is set", ErrValidation) |
| 640 | } |
| 641 | if !r.ClaimedAt.IsZero() && !r.LeaseUntil.IsZero() && !r.LeaseUntil.After(r.ClaimedAt) { |
| 642 | return fmt.Errorf("%w: task_run.lease_until must be after claimed_at", ErrValidation) |
| 643 | } |
| 644 | if !r.HeartbeatAt.IsZero() && !r.LeaseUntil.IsZero() && r.HeartbeatAt.After(r.LeaseUntil) { |
| 645 | return fmt.Errorf("%w: task_run.heartbeat_at must not be after lease_until", ErrValidation) |
| 646 | } |
| 647 | if !r.ClaimedAt.IsZero() && !r.HeartbeatAt.IsZero() && r.HeartbeatAt.Before(r.ClaimedAt) { |
| 648 | return fmt.Errorf("%w: task_run.heartbeat_at must not be before claimed_at", ErrValidation) |
| 649 | } |
| 650 | return nil |
| 651 | } |
| 652 | |
| 653 | func isCanonicalClaimTokenHash(value string) bool { |
| 654 | hash := strings.TrimSpace(value) |
no test coverage detected