Skip to content

Fix Gateway Job Spec marshaling#21695

Open
cedric-cordenier wants to merge 1 commit intodevelopfrom
gateway-yaml-fix
Open

Fix Gateway Job Spec marshaling#21695
cedric-cordenier wants to merge 1 commit intodevelopfrom
gateway-yaml-fix

Conversation

@cedric-cordenier
Copy link
Contributor

Requires

Supports

@cedric-cordenier cedric-cordenier requested a review from a team as a code owner March 25, 2026 13:01
Copilot AI review requested due to automatic review settings March 25, 2026 13:01
@cedric-cordenier cedric-cordenier requested a review from a team as a code owner March 25, 2026 13:01
@github-actions
Copy link
Contributor

👋 cedric-cordenier, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions
Copy link
Contributor

✅ No conflicts with other open PRs targeting develop

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Risk Rating: HIGH (changes the on-wire/serialized representation and decoding behavior of CRE job spec inputs across YAML/JSON entrypoints)

This PR aims to fix Gateway job spec marshaling by changing how JobSpecInput is represented and decoded, moving toward JSON-based marshaling and adding JSON struct tags to previously YAML-only types.

Changes:

  • Refactors JobSpecInput from a map[string]any to a json.RawMessage wrapper and switches UnmarshalTo/UnmarshalFrom to use encoding/json.
  • Updates CRE propose-job-spec input shape to hold Inputs as a pointer, and adjusts a TOML parsing site accordingly.
  • Adds json tags to standard capability / oracle factory related structs and updates a unit test to construct inputs via JSON marshaling.

Scrupulous human review recommended (high impact areas):

  • YAML ↔ inputs parsing behavior for jobs.ProposeJobSpecInput (existing YAML-driven flows/tests appear to depend on YAML decoding of inputs).
  • Backwards-compatibility of “empty/omitted inputs” behavior after switching to json.RawMessage.
  • Any downstream consumers expecting JobSpecInput map semantics (mutation, map literals, delete, etc.).

Suggested reviewers (CODEOWNERS):

  • @smartcontractkit/keystone, @smartcontractkit/operations-platform (owners for /deployment/cre)

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
deployment/cre/jobs/types/job_spec.go Reworks JobSpecInput to store raw JSON and decode via encoding/json.
deployment/cre/jobs/types/job_spec_test.go Updates tests to build JobSpecInput via JSON marshaling.
deployment/cre/jobs/propose_job_spec.go Changes Inputs to a pointer and adjusts precondition verification calls.
deployment/cre/jobs/pkg/types.go Adds JSON tags to oracle factory config structs.
deployment/cre/jobs/pkg/std_cap.go Adds JSON tags to StandardCapabilityJob fields for JSON-based decoding.
deployment/cre/jobs/operations/propose_std_cap_job.go Adjusts TOML unmarshal target from JobSpecInput to map[string]any.

}

func (j *JobSpecInput) UnmarshalJSON(d []byte) error {
j.RawMessage = d
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

UnmarshalJSON assigns the input byte slice directly to RawMessage. Per the encoding/json contract, UnmarshalJSON must copy the data if it needs to retain it after returning (the decoder may reuse the backing array). Make a copy of d before storing it to avoid subtle data corruption.

Suggested change
j.RawMessage = d
if d == nil {
j.RawMessage = nil
return nil
}
copied := make([]byte, len(d))
copy(copied, d)
j.RawMessage = json.RawMessage(copied)

Copilot uses AI. Check for mistakes.

return yaml.Unmarshal(bytes, target)
func (j JobSpecInput) UnmarshalTo(target any) error {
return json.Unmarshal([]byte(j.RawMessage), target)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

UnmarshalTo calls json.Unmarshal on j.RawMessage. When JobSpecInput is the zero value (RawMessage is nil/empty), json.Unmarshal returns "unexpected end of JSON input". If callers previously relied on an empty inputs object (or default/omitted inputs) being treated as an empty map, consider treating empty RawMessage as a no-op (or as {}) to preserve backwards-compatible behavior.

Suggested change
return json.Unmarshal([]byte(j.RawMessage), target)
// Treat empty or nil RawMessage as a no-op to preserve backward-compatible behavior
// where omitted/empty inputs are interpreted as default/zero-valued targets.
if len(j.RawMessage) == 0 {
return nil
}
// Also treat explicit JSON null as a no-op for consistency with default semantics.
if string(j.RawMessage) == "null" {
return nil
}
return json.Unmarshal(j.RawMessage, target)

Copilot uses AI. Check for mistakes.
Comment on lines 60 to 67
switch config.Template {
case job_types.EVM:
if err := verifyEVMJobSpecInputs(config.Inputs); err != nil {
if err := verifyEVMJobSpecInputs(*config.Inputs); err != nil {
return fmt.Errorf("invalid inputs for EVM job spec: %w", err)
}
case job_types.Solana:
if err := verifySolanaJobSpecInputs(config.Inputs); err != nil {
if err := verifySolanaJobSpecInputs(*config.Inputs); err != nil {
return fmt.Errorf("invalid inputs for EVM job spec: %w", err)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

VerifyPreconditions dereferences config.Inputs (e.g., *config.Inputs) before checking whether Inputs is nil. If inputs are omitted in the request/YAML, this will panic instead of returning a validation error. Move the config.Inputs == nil check to before the switch (and before any dereference), or avoid dereferencing until after the nil check.

Copilot uses AI. Check for mistakes.
@trunk-io
Copy link

trunk-io bot commented Mar 25, 2026

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@cl-sonarqube-production
Copy link

Comment on lines +12 to +14
type JobSpecInput struct {
json.RawMessage
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
type JobSpecInput struct {
json.RawMessage
}
type JobSpecInput json.RawMessag

Would this work too?

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.

3 participants