Share an HTML report from AWS CodeBuild

CodeBuild has reports. They are not your report.

A report group parses JUnit XML, Cucumber JSON, or a coverage format and renders AWS's own summary of it in the console. That summary is useful and it is not the page your test runner produced — the Playwright trace, the pytest --html output, the coverage tree with the annotated source. Those are artifacts, and artifacts go to S3, where an index.html sits as an object that nothing will render until you decide to make it renderable.

Deciding to make it renderable means:

  • a bucket policy, negotiated against Block Public Access;
  • either S3 static website hosting (public, and now you own a public bucket) or a presigned URL (private, and it expires — usually before the person you sent it to opens it);
  • a lifecycle rule, so the bucket does not accumulate every build forever;
  • and, at the end of all that, still no way for anyone to comment on what they are looking at.

Publish from the buildspec instead

Put a scoped token (reports:write only) in Secrets Manager, reference it from env, create the report once, and PATCH that id from every build:

version: 0.2

env:
  variables:
    COMMA_REPORT_ID: "rep_xxxxxxxx"
  secrets-manager:
    COMMA_API_TOKEN: comma/ci:token

phases:
  build:
    commands:
      - pytest --cov --cov-report=html
    finally:
      - |
        curl -fsS -X PATCH \
          "https://commareports.com/api/v1/reports/$COMMA_REPORT_ID" \
          -H "Authorization: Bearer $COMMA_API_TOKEN" \
          -H "Content-Type: application/json" \
          -d "$(jq -n --rawfile html htmlcov/index.html \
                --arg title "Coverage — ${CODEBUILD_RESOLVED_SOURCE_VERSION:0:7}" \
                '{title: $title, html: $html}')"
      - echo "Report → https://commareports.com/p/$COMMA_REPORT_ID"

artifacts:
  files:
    - htmlcov/**/*

Three things matter here:

  • finally runs regardless. Buildspec version 0.2 runs a phase's finally block whether the phase's commands passed or failed, which is the whole reason the red builds get a readable report at all.
  • secrets-manager keeps the token out of the log. CodeBuild resolves it into the environment without echoing it, and the build role needs secretsmanager:GetSecretValue on that one secret — not a wildcard.
  • The artifacts block stays. Keeping the S3 copy costs nothing for whoever wants the raw files; the published report is for everyone who just wants to read it.

What the published copy adds

  • A URL that renders, with no bucket. The HTML is stored verbatim and served inside a sandboxed iframe with scripts enabled, so an interactive report stays interactive. No policy, no Block Public Access decision, no presigned expiry.
  • One address across every build. Revisions accumulate and any two can be diffed — "what changed since the last green build" has an answer.
  • Readers without an AWS account. Visibility is private, team, domain-gated, or link, decided per report and independent of IAM.
  • Comments anchored to the content. A reviewer highlights the regressed number and pins a thread to it — see commenting on HTML.

Limits

  • HTML body: 5 MB. Traces, videos and archives go in as assets at 25 MB per file, 250 MB per report.
  • A report that fetches sibling data files at view time can't, from the sandbox — publish a static digest with the archive attached, as in sharing an Allure report.
  • Rate limit: 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Create your first report →

Related