diff --git a/README.md b/README.md index 2efdd24..453d50a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,6 @@ jobs: | `s3-key` | conditional | — | Object key. Required if `s3-bucket` is set. Supports `{version}` and `{filename}` placeholders. | | `s3-endpoint-url` | no | — | Custom endpoint for S3-compatible storage (MinIO, R2, etc.) | | `s3-region` | no | `us-east-1` | AWS region | -| `s3-acl` | no | — | Canned ACL applied to the uploaded object (e.g. `public-read`). Empty = no ACL sent. Modern AWS buckets with Object Ownership = "Bucket owner enforced" reject any ACL — leave this unset for those. | AWS credentials (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optionally `AWS_SESSION_TOKEN`) are read from the standard environment, **not** from action inputs. diff --git a/action.yml b/action.yml index b966b6c..746fb6e 100644 --- a/action.yml +++ b/action.yml @@ -26,7 +26,6 @@ inputs: s3-key: { description: "Object key. Supports {version} and {filename} placeholders.", required: false } s3-endpoint-url: { description: "Custom endpoint for S3-compatible storage (MinIO, R2, etc.)", required: false } s3-region: { description: "AWS region", required: false, default: "us-east-1" } - s3-acl: { description: "Canned ACL applied to the uploaded object (e.g. public-read). Empty = no ACL sent.", required: false } outputs: version: { description: "Resolved version string", value: "${{ steps.run.outputs.version }}" } @@ -59,7 +58,6 @@ runs: INPUT_S3_KEY: ${{ inputs.s3-key }} INPUT_S3_ENDPOINT_URL: ${{ inputs.s3-endpoint-url }} INPUT_S3_REGION: ${{ inputs.s3-region }} - INPUT_S3_ACL: ${{ inputs.s3-acl }} run: | set -euo pipefail go install "lmika.dev/${{ github.action_repository }}/cmd/wails-release@${{ github.action_ref }}" diff --git a/cmd/wails-release/main.go b/cmd/wails-release/main.go index 425378d..4e76341 100644 --- a/cmd/wails-release/main.go +++ b/cmd/wails-release/main.go @@ -169,12 +169,11 @@ func run(ctx context.Context) error { } key := upload.RenderKey(cfg.S3Key, resolvedVersion, artifactName) s3URL, err = upload.Upload(ctx, client, upload.Opts{ - Bucket: cfg.S3Bucket, Key: key, FilePath: zipPath, ACL: cfg.S3ACL, + Bucket: cfg.S3Bucket, Key: key, FilePath: zipPath, }) if err != nil { return err } - fmt.Println("Uploaded to:", upload.HTTPSURL(cfg.S3Bucket, key, cfg.S3Region, cfg.S3EndpointURL)) } // 8. Outputs (fixed order so partial-write failures are reproducible) diff --git a/internal/config/config.go b/internal/config/config.go index 6f40f0e..b0f0dac 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -28,7 +28,6 @@ type Config struct { S3Key string S3EndpointURL string S3Region string - S3ACL string } // Load reads the action's INPUT_* environment variables. @@ -52,7 +51,6 @@ func Load(get func(string) string) *Config { S3Key: get("INPUT_S3_KEY"), S3EndpointURL: get("INPUT_S3_ENDPOINT_URL"), S3Region: getOr(get, "INPUT_S3_REGION", "us-east-1"), - S3ACL: get("INPUT_S3_ACL"), } return c } @@ -117,14 +115,6 @@ func (c *Config) Validate() error { if c.S3Bucket != "" && c.S3Key == "" { return fmt.Errorf("s3-bucket is set but s3-key is empty") } - if c.S3ACL != "" { - switch c.S3ACL { - case "private", "public-read", "public-read-write", "authenticated-read", - "aws-exec-read", "bucket-owner-read", "bucket-owner-full-control": - default: - return fmt.Errorf("s3-acl must be one of private, public-read, public-read-write, authenticated-read, aws-exec-read, bucket-owner-read, bucket-owner-full-control (got %q)", c.S3ACL) - } - } return nil } diff --git a/internal/upload/upload.go b/internal/upload/upload.go index 0bef957..1c1bac6 100644 --- a/internal/upload/upload.go +++ b/internal/upload/upload.go @@ -9,7 +9,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/aws/aws-sdk-go-v2/service/s3/types" ) // PutObjectAPI is the subset of *s3.Client used here. Tests inject a fake. @@ -22,10 +21,6 @@ type Opts struct { Bucket string Key string FilePath string - // ACL, if set, is applied to the uploaded object as a canned ACL - // (e.g. "public-read"). Empty means no ACL is sent — required for - // buckets with Object Ownership = "Bucket owner enforced". - ACL string } // RenderKey substitutes {version} and {filename} placeholders. @@ -42,33 +37,16 @@ func Upload(ctx context.Context, c PutObjectAPI, o Opts) (string, error) { } defer f.Close() - in := &s3.PutObjectInput{ + if _, err := c.PutObject(ctx, &s3.PutObjectInput{ Bucket: aws.String(o.Bucket), Key: aws.String(o.Key), Body: f, - } - if o.ACL != "" { - in.ACL = types.ObjectCannedACL(o.ACL) - } - if _, err := c.PutObject(ctx, in); err != nil { + }); err != nil { return "", fmt.Errorf("s3 put: %w", err) } return fmt.Sprintf("s3://%s/%s", o.Bucket, o.Key), nil } -// HTTPSURL returns the HTTPS form of an upload location. For AWS S3 it uses -// the regional virtual-hosted form; for a custom endpoint it appends the -// bucket and key path-style, matching how NewClient configures the client. -// -// The bucket may still be private — this is purely the URL where the object -// would be served if it (or its bucket) were publicly readable. -func HTTPSURL(bucket, key, region, endpointURL string) string { - if endpointURL != "" { - return strings.TrimRight(endpointURL, "/") + "/" + bucket + "/" + key - } - return fmt.Sprintf("https://%s.s3.%s.amazonaws.com/%s", bucket, region, key) -} - // WriteFileForTest is exposed for use from this package's tests. func WriteFileForTest(path string, b []byte) error { return os.WriteFile(path, b, 0o600) diff --git a/internal/upload/upload_test.go b/internal/upload/upload_test.go index 228bff8..61fc80b 100644 --- a/internal/upload/upload_test.go +++ b/internal/upload/upload_test.go @@ -29,49 +29,6 @@ func TestRenderKey(t *testing.T) { } } -func TestHTTPSURL(t *testing.T) { - cases := []struct { - name string - bucket, key string - region string - endpoint string - want string - }{ - { - name: "aws regional virtual-hosted", - bucket: "my-bucket", key: "releases/1.2.3/App.app.zip", - region: "ap-southeast-2", - want: "https://my-bucket.s3.ap-southeast-2.amazonaws.com/releases/1.2.3/App.app.zip", - }, - { - name: "aws us-east-1 still uses regional form", - bucket: "my-bucket", key: "k", - region: "us-east-1", - want: "https://my-bucket.s3.us-east-1.amazonaws.com/k", - }, - { - name: "custom endpoint path-style", - bucket: "releases", key: "myapp/1.0.0/App.app.zip", - region: "auto", endpoint: "https://my-minio.example.com", - want: "https://my-minio.example.com/releases/myapp/1.0.0/App.app.zip", - }, - { - name: "custom endpoint with trailing slash is normalised", - bucket: "b", key: "k", - region: "auto", endpoint: "https://example.com/", - want: "https://example.com/b/k", - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - got := upload.HTTPSURL(c.bucket, c.key, c.region, c.endpoint) - if got != c.want { - t.Fatalf("got %q\nwant %q", got, c.want) - } - }) - } -} - type fakePut struct { calls []*s3.PutObjectInput } @@ -104,34 +61,6 @@ func TestUpload_CallsPutObjectWithCorrectInputs(t *testing.T) { } } -func TestUpload_ForwardsACLWhenSet(t *testing.T) { - tmp := writeTempFile(t, "hello") - c := &fakePut{} - - if _, err := upload.Upload(context.Background(), c, upload.Opts{ - Bucket: "b", Key: "k", FilePath: tmp, ACL: "public-read", - }); err != nil { - t.Fatalf("unexpected: %v", err) - } - if string(c.calls[0].ACL) != "public-read" { - t.Fatalf("ACL got %q want public-read", c.calls[0].ACL) - } -} - -func TestUpload_OmitsACLWhenEmpty(t *testing.T) { - tmp := writeTempFile(t, "hello") - c := &fakePut{} - - if _, err := upload.Upload(context.Background(), c, upload.Opts{ - Bucket: "b", Key: "k", FilePath: tmp, - }); err != nil { - t.Fatalf("unexpected: %v", err) - } - if c.calls[0].ACL != "" { - t.Fatalf("ACL got %q want empty (no ACL sent)", c.calls[0].ACL) - } -} - func TestUpload_FailsWhenFileMissing(t *testing.T) { _, err := upload.Upload(context.Background(), &fakePut{}, upload.Opts{ Bucket: "b",