Skip to content

Added Partner Integration Guide - #47

Open
ievdokdm wants to merge 2 commits into
flutter:mainfrom
ievdokdm:partner-section
Open

ievdokdm wants to merge 2 commits into
flutter:mainfrom
ievdokdm:partner-section

Conversation

@ievdokdm

@ievdokdm ievdokdm commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Added Partner Integration Guide

Pre-launch Checklist

  • I read RFC 000.0001: Taxonomy and followed the file and path naming and metadata standards.
  • I read RFC 000.0002: Process and confirmed this proposal meets the threshold for a full RFC.
  • I read and agree to the Code of Conduct.
  • I signed the CLA.
  • I have linked an issue from flutter/flutter with the label design doc.
  • All existing and new tests are passing.
  • I have enabled "Allow edits from maintainers" on this PR so the bot can automatically assign an RFC number (or I will run dart run bin/assign_rfc_number.dart locally when instructed).

If you need help, consider asking for advice on the #hackers channel on Discord.

| `branches` | Yes | List of target branch patterns to trigger on (e.g., `["master", "beta", "stable"]`). |
| `webhook_url` | Yes | Public `https://` URL hosted by the partner to receive CI trigger requests from Cocoon. |
| `keys_url` | Yes | Public, unauthenticated `https://` JWKS URL hosted by the partner to serve Ed25519 public keys. |
| `status_url` | No | Public `https://` URL hosted by the partner to handle manual on-demand status queries from Cocoon. |

@loic-sharma loic-sharma Nov 12, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This doc uses both webhook_url/keys_url/status_url and partner_webhook_url/partner_keys_url/partner_status_url terminology. What do you think of being consistent and using the partner_ prefix everywhere? This also has the benefit of making it easier for partners to keep track of which URLs are partner URLs, and which URLs are Cocoon URLs.


* All partner URLs (`webhook_url`, `keys_url`, `status_url`, and log `details[].url` links) MUST use the `https://` scheme and resolve to public IP addresses (private, loopback, and link-local IP ranges are blocked).
* Cocoon does not follow HTTP redirects to disallowed hosts or non-HTTPS schemes.
* Because the Flutter build dashboard is public, `message` summaries and `details[].url` links submitted to Cocoon MUST NOT contain Personally Identifiable Information (PII), internal hostnames, or confidential secrets.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We haven't explained what message and details[].url are yet. What do you think of moving this content to both the partner status URL section and the Cocoon callback endpoint section?

#### 9.3.1. Workflow Summary

1. **Post-Submit Trigger (`Cocoon -> Partner`):**
* When a PR is merged into a configured branch on `flutter/flutter`, Cocoon sends an `HTTP POST` request with a signed JWT to the partner's `webhook_url`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we quickly mention the uid here? Steps 2/3/5 mention the uid, but it might not be obvious to partners that this is where that uid first comes from.

end
```

#### 9.3.1. Workflow Summary

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I really like this section, it's a great intro to the protocol. What do you think of making this the second section, after the configuration section? I think that might help a reader get a good high-level understanding before we drill down into specifics like authentication. Just a thought, up to you.


##### 9.4.2.1. Cocoon Public JWKS Endpoint

* **URL:** `GET <cocoon_keys_url>`

@loic-sharma loic-sharma Nov 12, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we add a real URL here? Maybe something like GET https://dashboard.flutter.dev/api/v1/partner/keys?

}
```

* **Expected Partner HTTP Response Codes:**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we specify that the partner should return a HTTP status 400 if it doesn't not recognize the version?

"iat": 1774962000,
"exp": 1774962300,
"version": "v1",
"data": {

@loic-sharma loic-sharma Nov 12, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For all keys under the data object can we document:

  • The type of the key (string, integer, etc)
  • Whether the key is required or optional. (Is pr optional?)
  • A quick description of the value
  • If the value is an enum, the allowed values, and what the partner should do if the value is unknown

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comment for all other endpoints :)

}
```

##### 9.4.1.2. Partner Webhook Listener Endpoint (Required)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you skip the workflow summary section, it might not be immediately obvious what this endpoint should do. Could we add a * **Summary:** ... to each endpoint that copies the relevant information from the workflow summary section?

}
```

* **Expected Partner HTTP Response Codes:**

@loic-sharma loic-sharma Nov 12, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we specify the HTTP response body as well?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be nice if partners can use the body to provide debugging information in the event of failures? Something like:

{
  "message": "Hello world"
}

This would be a slight amendment to the RFC, but it seems like a change worth considering.

* **URL:** `POST <partner_webhook_url>`
* **Authentication:** Request body is a raw JWT signed by Cocoon (`iss: "cocoon"`, `aud: "<partner_webhook_url>"`).
* **Constraints:** Partner MUST respond within **30 seconds** (acknowledge receipt before running tests); maximum response body size is **64 KB**.
* **Backward/Forward Compatibility:** Partner parsers MUST ignore unrecognized JSON fields in `data`.

@loic-sharma loic-sharma Nov 12, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we specify that partners must fail if the version is unrecognized? This would make it easier for us to do breaking changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added

}
]
}
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we repeat the PII / public logs warning here as well?

Because the Flutter build dashboard is public, message summaries and details[].url links submitted to Cocoon MUST NOT contain Personally Identifiable Information (PII), internal hostnames, or confidential secrets.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added

| `in_progress` | Non-Terminal | Task or test is currently executing. Allowed only in optional start callbacks and `GET /status` responses. |
| `succeeded` | Terminal (Success) | All tests passed. |
| `neutral` | Terminal (Success) | Only flaky tests failed (non-failing outcome). |
| `skipped` | Terminal (Success) | Tests were skipped. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If flaky tests failed and tests were skipped, should the partner return neutral or skipped?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

its up to partner, I think

| `400 Bad Request` | Payload schema validation error or non-HTTPS log URL. | Do not retry; fix payload construction. |
| `401 Unauthorized` | Unknown `kid`, expired token, or invalid JWT signature. | Do not retry; verify signing key and JWKS endpoint. |
| `404 Not Found` | `data.uid` does not exist in Cocoon. | Do not retry. |
| `409 Conflict` | Terminal status was already processed for `data.uid`. | Treat as idempotent success; do not retry. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The partner can send a start status callback with the in_progress status. What happens if they send multiple in_progress statuses? Will we accept just the first one and return 409 Conflicts for subsequent callbacks? If yes, let's call that out here as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added: or a duplicate in_progress status

* **Verifying Requests from Cocoon (Partner Inbound):**
1. Extract the JWT from the HTTP request body (`POST <webhook_url>`) or the `Authorization: Bearer <Signed JWT>` header (`GET <status_url>`).
2. Verify that the header specifies `"alg": "EdDSA"` and `"typ": "JWT"` ([RFC 8725](https://www.rfc-editor.org/info/rfc8725/#section-3)).
3. Look up the public key matching the header's `kid` from Cocoon's public JWKS endpoint (caching the key set and refreshing on cache miss).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we provide guidance to partners on cache miss cooldown? If a partner forgets this, an attacker could send random kids to the partner to make the partner hammer Cocoon's endpoint.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added JWKS Caching & Cache-Miss Cooldown (DoS Prevention) recomendation

}
```

* **HTTP Response (`200 OK`):**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What are the response codes here for different failure scenarios?

  • uid doesn't exist
  • Client or authentication error
  • Temporary overload, timeout, or server error.

Also, it might be worth specifying that you should return a 200 even if the test failed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added Expected Partner HTTP Response Codes section


---

## 9. Partner Integration Guide

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hey, should this be a separate document that links back to the RFC? I think this would make it a little nicer for partners to read this content, but I don't feel too strongly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@jtmcdole say it should be part of RFC

@loic-sharma loic-sharma Nov 13, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

OK sounds good 👍

@loic-sharma loic-sharma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good overall, my comments are just nitpicks :)

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.

2 participants