CORS
CORS is a rule a browser applies before a web page may read something from another address. The
page at app.plune.ai and your bucket are two different addresses, so the browser asks the bucket
“may this page read you?” and reads the answer only if the bucket says yes. The bucket says yes
when it has a CORS rule that names the page’s address.
What needs it and what does not
Section titled “What needs it and what does not”| File | Needs a CORS rule | Why |
|---|---|---|
| Screenshot | no | shown with an <img> tag, and a tag does not read the file, it only displays it |
| Video | no | shown with a <video> tag, the same |
| Text, JSON, log | yes | the dashboard reads the file itself, to show it in a window |
| Trace | yes | the dashboard reads the file itself and hands it to the trace viewer in the window; the viewer’s own address needs no rule |
| A person adding a file in the dashboard | yes | the browser sends the file to the bucket itself, by a link Plune signed for it |
| The CI uploading | no | it uploads from a machine, not from a browser |
So a bucket with no rule at all works, and shows screenshots and videos; text files and traces will refuse
to open — and a file a person adds in the dashboard does not
get there: its row says the connection dropped. Settings → Storage tells you which: its check CORS lets … read and add files fails
with CORS missing when the dashboard may not
read. With #1341 it asks about putting a file too: a rule without PUT, or without the content-type
header, fails it with CORS put missing, and
How to fix opens the rule.
The rule
Section titled “The rule”One rule, and as little in it as possible: GET and PUT, the one header content-type,
and only from the address of the dashboard.
| Dashboard | Address to allow |
|---|---|
| Production | https://app.plune.ai |
| Beta | https://beta.plune.ai |
Do not allow * (every address), and do not allow DELETE: a browser reads files and puts a person’s
new ones, each by a link Plune signed for that one file — the rule lets the page send the request, the
link is the right to make it. The CI does not go through CORS.
If one bucket serves both the beta and production dashboards, list both addresses in AllowedOrigins.
AWS S3 and Cloudflare R2
Section titled “AWS S3 and Cloudflare R2”Both take the same JSON in their consoles:
[ { "AllowedOrigins": ["https://app.plune.ai"], "AllowedMethods": ["GET", "PUT"], "AllowedHeaders": ["content-type"], "MaxAgeSeconds": 3600 }]Where to paste it: AWS S3, Cloudflare R2.
Other services
Section titled “Other services”Every service has its own place for the rule, and some a different format; they are on
Other S3-compatible storage, under each service. A service that can
only take the S3 API’s XML wants the same content: the origin, GET and PUT, the header and an age.
Check it
Section titled “Check it”In Settings → Storage press Test connection. The check CORS lets <address> read and add files asks
your bucket what it would tell a browser at the dashboard’s address, the way a browser asks: whether it may
read (GET), and then — with #1341 — whether it may put a file with its content-type (PUT). It passes
when both answers are yes. (The other checks write a small test file into your folder and delete it again.)
A rule can take a moment to apply — a few seconds, and in the rare case up to half a minute on R2 — so if the check fails right after you saved the rule, wait and press Test connection again.