Skip to content

Manual (Console)

1. Use an existing private S3 bucket

1.1 Ensure bucket privacy

aws s3api get-public-access-block --bucket <BUCKET>

Expected flags are all true. If you need to enforce them:

aws s3api put-public-access-block --bucket <BUCKET> --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

aws s3api put-bucket-ownership-controls --bucket <BUCKET> \
  --ownership-controls 'OwnershipControls={Rules=[{ObjectOwnership=BucketOwnerEnforced}]}'

1.2 Grant least-privilege IAM to the publisher

Attach this policy to the IAM user or role that will run publish-allure. Replace placeholders.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListScoped",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::<BUCKET>",
      "Condition": { "StringLike": { "s3:prefix": ["<PROJECT>/*"] } }
    },
    {
      "Sid": "ObjectCrudScoped",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:CopyObject",
        "s3:PutObjectTagging",
        "s3:GetObjectTagging"
      ],
      "Resource": "arn:aws:s3:::<BUCKET>/<PROJECT>/*"
    }
  ]
}

Typical values: <PROJECT> is your logical project like payments.


2. New minimal private bucket instead

If you do not have a bucket yet:

export AWS_REGION=eu-west-1
aws s3api create-bucket --bucket <BUCKET> --region $AWS_REGION \
  --create-bucket-configuration LocationConstraint=$AWS_REGION

aws s3api put-public-access-block --bucket <BUCKET> --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

aws s3api put-bucket-ownership-controls --bucket <BUCKET> \
  --ownership-controls 'OwnershipControls={Rules=[{ObjectOwnership=BucketOwnerEnforced}]}'

Then attach the IAM policy from section 1.2 to your publisher principal.


2.5 CloudFront + S3 Creation Order (Important)

When setting up CloudFront access to your S3 bucket, follow this sequence strictly to avoid invalid SourceArn references.

Step 1 – Create or identify your S3 bucket

Ensure your private bucket exists and has public access fully blocked. Do not yet attach any CloudFront-related policy.

Step 2 – Create your CloudFront distribution

  • Set the origin domain as the bucket’s REST endpoint, e.g. bucket-name.s3.eu-west-1.amazonaws.com.
  • Use Origin Access Control (OAC) (not OAI).
  • Record both the distribution ID (shown below as <DISTRIBUTION_ID>) and the distribution ARN (e.g. arn:aws:cloudfront::<ACCOUNT_ID>:distribution/<DISTRIBUTION_ID>). Use your actual generated values instead of the placeholder.

CloudFront Setup Page 1

  • Choose your S3 bucket as the origin domain.
  • Enable Origin Access Control (OAC) to restrict access securely.

CloudFront Setup Page 2

  • Review default caching and security settings.
  • You can leave these options as default for typical use.

CloudFront Setup Page 3

  • Verify all distribution settings are correct.
  • Click “Create distribution” to finalize setup.

Step 3 – Verify the CloudFront read policy on your bucket

The AWS Console often auto-adds the necessary bucket policy to allow CloudFront access. You should verify this policy exists and tighten it if needed to restrict access to your distribution’s ARN. Below is an example policy to add if missing or to tighten:

{
  "Sid": "AllowCloudFrontServicePrincipalRead",
  "Effect": "Allow",
  "Principal": {
    "Service": "cloudfront.amazonaws.com"
  },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::<BUCKET>/*",
  "Condition": {
    "StringEquals": {
      "AWS:SourceArn": "arn:aws:cloudfront::<ACCOUNT_ID>:distribution/<DISTRIBUTION_ID>"
    }
  }
}

Step 4 – Test connectivity

Run:

aws s3api get-bucket-policy --bucket <BUCKET>

Confirm the SourceArn matches your current CloudFront distribution. Replace if you recreate the distribution.


CloudFront UI Setup

The following steps walk through CloudFront + OAC configuration in the AWS Console.

3. Optional CloudFront with OAC

Use CloudFront if you need a friendly HTTPS viewer URL and SPA routing support.

3.1 Create distribution and OAC

  • Origin domain: the S3 bucket REST endpoint like BUCKET.s3.eu-west-1.amazonaws.com
  • Origin access: Origin Access Control enabled
  • Compress objects: on

3.2 Bucket policy to allow CloudFront reads

Add alongside your existing bucket policy statements:

{
  "Sid": "AllowCloudFrontOAC",
  "Effect": "Allow",
  "Principal": { "Service": "cloudfront.amazonaws.com" },
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::<BUCKET>/*",
  "Condition": {
    "StringEquals": {
      "AWS:SourceArn": "arn:aws:cloudfront::<ACCOUNT_ID>:distribution/<DISTRIBUTION_ID>"
    }
  }
}

3.3 CloudFront error response mapping for SPA

Configure error responses:

  • 403 to /index.html with response code 200 and TTL 0
  • 404 to /index.html with response code 200 and TTL 0

This makes deep links such as #/graphs work.


4. First run

Create a minimal allure results folder:

mkdir -p allure-results
echo '{}' > allure-results/result.json

Dry-run preflight:

publish-allure \
  --bucket <BUCKET> \
  --prefix <PROJECT>/<BRANCH> \
  --project <PROJECT> \
  --branch <BRANCH> \
  --cloudfront https://<CF_DOMAIN> \
  --check --dry-run \
  --summary-json plan.json

Inspect plan.json, then perform a real publish:

publish-allure \
  --bucket <BUCKET> \
  --prefix <PROJECT>/<BRANCH> \
  --project <PROJECT> \
  --branch <BRANCH> \
  --cloudfront https://<CF_DOMAIN>

Open in the browser:

https://<CF_DOMAIN>/<PROJECT>/<BRANCH>/latest/
https://<CF_DOMAIN>/<PROJECT>/<BRANCH>/runs/index.html
https://<CF_DOMAIN>/<PROJECT>/<BRANCH>/runs/trend.html

Published Result Example


5. Verification and common pitfalls

  • 301 redirect: your client region does not match the bucket region. Export the correct AWS_REGION.
  • 403 via CloudFront: OAC not trusted or SourceArn does not match. Fix the bucket policy.
  • SPA deep link blank: add 403 and 404 error mappings to /index.html.
  • Trend missing after first publish: a second publish will show a trend once history exists and ListBucket is allowed on the prefix.

6. Optional lifecycle and KMS

Lifecycle

Tag objects with ttl-days using the CLI flag and pair with an S3 lifecycle:

aws s3api put-bucket-lifecycle-configuration --bucket <BUCKET> --lifecycle-configuration '{
  "Rules": [
    {
      "ID": "expire-old-runs",
      "Filter": {"Prefix": "<PROJECT>/"},
      "Status": "Enabled",
      "Expiration": {"Days": 90}
    }
  ]
}'

KMS

If your bucket enforces SSE-KMS, grant the publisher role minimal CMK permissions and run with:

publish-allure ... --sse aws:kms --sse-kms-key-id <KEY_ARN>

Return to prerequisites & quick reference in setup.md or choose another method: AWS CLI