Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions providers/cloudflare/exclusions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1090,34 +1090,6 @@
"reason": "Cloudflare OpenAPI does not declare an API token permission group; OAuth authority cannot be proven.",
"permissionGroups": null
},
{
"method": "GET",
"path": "/accounts/{account_id}/containers/applications",
"operationId": "listApplications",
"reason": "Cloudflare OpenAPI does not declare an API token permission group; OAuth authority cannot be proven.",
"permissionGroups": null
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/applications",
"operationId": "createApplication",
"reason": "Cloudflare OpenAPI does not declare an API token permission group; OAuth authority cannot be proven.",
"permissionGroups": null
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/applications/{application_id}/rollouts",
"operationId": "createApplicationRollout",
"reason": "Cloudflare OpenAPI does not declare an API token permission group; OAuth authority cannot be proven.",
"permissionGroups": null
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/registries/{domain}/credentials",
"operationId": "generateImageRegistryCredentials",
"reason": "Cloudflare OpenAPI does not declare an API token permission group; OAuth authority cannot be proven.",
"permissionGroups": null
},
{
"method": "DELETE",
"path": "/accounts/{account_id}/custom_ns/{custom_ns_id}",
Expand Down
46 changes: 46 additions & 0 deletions providers/cloudflare/wrangler-compatibility-operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,52 @@
"version": "4.120.0",
"source": "https://github.com/cloudflare/workers-sdk/tree/wrangler%404.120.0/packages/wrangler",
"operations": [
{
"method": "GET",
"path": "/accounts/{account_id}/containers/me",
"operationId": "wrangler-containers-get-account",
"scopes": ["containers.read", "containers.write"]
},
{
"method": "GET",
"path": "/accounts/{account_id}/containers/applications",
"operationId": "wrangler-containers-list-applications",
"officialOperationId": "listApplications",
"scopes": ["containers.read", "containers.write"]
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/applications",
"operationId": "wrangler-containers-create-application",
"officialOperationId": "createApplication",
"scopes": ["containers.write"]
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/applications/{application_id}/rollouts",
"operationId": "wrangler-containers-create-application-rollout",
"officialOperationId": "createApplicationRollout",
"scopes": ["containers.write"]
},
{
"method": "GET",
"path": "/accounts/{account_id}/containers/dash/applications",
"operationId": "wrangler-containers-list-dash-applications",
"scopes": ["containers.read", "containers.write"]
},
{
"method": "GET",
"path": "/accounts/{account_id}/containers/dash/applications/{application_id}/instances",
"operationId": "wrangler-containers-list-dash-application-instances",
"scopes": ["containers.read", "containers.write"]
},
{
"method": "POST",
"path": "/accounts/{account_id}/containers/registries/{domain}/credentials",
"operationId": "wrangler-containers-generate-registry-credentials",
"officialOperationId": "generateImageRegistryCredentials",
"scopes": ["containers.write"]
},
{
"method": "GET",
"path": "/accounts/{account_id}/workers/services/{service_name}",
Expand Down
2 changes: 1 addition & 1 deletion public/cloudflare/openapi.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/providers/cloudflare/operation-permissions.ts

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions test/providers/cloudflare-adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,34 @@ describe('Cloudflare adapter', () => {
expect(upstream).toHaveBeenCalledTimes(1)
})

it('forwards the pinned Wrangler Container list and deployment operations', async () => {
const operations = [
['GET', '/accounts/account-1/containers/me', 'containers.read'],
['GET', '/accounts/account-1/containers/applications', 'containers.read'],
['POST', '/accounts/account-1/containers/applications', 'containers.write'],
['POST', '/accounts/account-1/containers/applications/app-1/rollouts', 'containers.write'],
['GET', '/accounts/account-1/containers/dash/applications', 'containers.read'],
['GET', '/accounts/account-1/containers/dash/applications/app-1/instances', 'containers.read'],
['POST', '/accounts/account-1/containers/registries/registry.example/credentials', 'containers.write'],
] as const

for (const [method, path, scope] of operations) {
const upstream = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
const request = input instanceof Request ? input : new Request(input, init)
expect(request.url).toBe(`https://api.cloudflare.com/client/v4${path}`)
expect(request.method).toBe(method)
return Response.json({ success: true, result: [] })
})
const { app, credential } = fixture({ upstream, principal: principal([scope]) })

const response = await app.request(`/cloudflare${path}`, { method })

expect(response.status).toBe(200)
expect(credential).toHaveBeenCalledWith('user-1')
expect(upstream).toHaveBeenCalledTimes(1)
}
})

it('[spec: cloudflare-adapter/cloudflare-native-tool-scope-challenge] fails closed and reports operation scope alternatives', async () => {
const unpublished = fixture()
expect((await unpublished.app.request('/cloudflare/not-an-operation')).status).toBe(404)
Expand Down
34 changes: 32 additions & 2 deletions test/providers/cloudflare-openapi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ describe('generated Cloudflare OpenAPI', () => {
expect(source.commit).toMatch(/^[a-f0-9]{40}$/)
expect(source.openapiSha256).toMatch(/^[a-f0-9]{64}$/)
expect(catalog.sha256).toBe(createHash('sha256').update(JSON.stringify(catalog.scopes)).digest('hex'))
expect(cloudflareOperations).toHaveLength(2663)
expect(exclusions.operations).toHaveLength(630)
expect(cloudflareOperations).toHaveLength(2670)
expect(exclusions.operations).toHaveLength(626)
const additiveCompatibilityOperations = wranglerCompatibility.operations.filter(
(operation: { officialOperationId?: string }) => !operation.officialOperationId,
)
Expand Down Expand Up @@ -124,6 +124,36 @@ describe('generated Cloudflare OpenAPI', () => {
})
}
})

it('publishes the pinned Wrangler Container list and deployment operations', async () => {
const openapi = await json('public/cloudflare/openapi.json')
const expected = [
['GET', '/accounts/{account_id}/containers/me', ['containers.read', 'containers.write']],
['GET', '/accounts/{account_id}/containers/applications', ['containers.read', 'containers.write']],
['POST', '/accounts/{account_id}/containers/applications', ['containers.write']],
['POST', '/accounts/{account_id}/containers/applications/{application_id}/rollouts', ['containers.write']],
['GET', '/accounts/{account_id}/containers/dash/applications', ['containers.read', 'containers.write']],
[
'GET',
'/accounts/{account_id}/containers/dash/applications/{application_id}/instances',
['containers.read', 'containers.write'],
],
['POST', '/accounts/{account_id}/containers/registries/{domain}/credentials', ['containers.write']],
] as const

for (const [method, path, scopes] of expected) {
expect(cloudflareOperations.find((operation) => operation.method === method && operation.path === path)).toEqual(
expect.objectContaining({ method, path, scopes }),
)
expect(openapi.paths[path]?.[method.toLowerCase()].security).toEqual(
scopes.map((scope) => ({ realmrootOidc: [scope] })),
)
expect(openapi.paths[path]?.[method.toLowerCase()]['x-realmroot-compatibility-source']).toMatchObject({
package: 'wrangler',
version: '4.120.0',
})
}
})
})

async function json(path: string) {
Expand Down