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
184 changes: 184 additions & 0 deletions trusted-profiles/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Trusted Profiles

In the IBM Cloud, when authenticating with other services such as Cloud
Object Storage or Secrets Manager, using trusted profiles is a way to
authenticate without any API keys being used. This eliminates the risk of
those being leaked or stolen by a malicious user who uses them to access your
IBM Cloud resources.

You can read more about trusted profiles in the
[IBM Cloud documentation](https://cloud.ibm.com/docs/account?topic=account-create-trusted-profile).

The samples in this directory show how to use the trusted profile in your code
using the IBM Cloud SDK that exists for Go, Java, Node, and Python.

If you are using a different programming language, then you can still use
trusted profiles, but must implement the interaction with
[IAM to retrieve an access token for a compute resource token](https://cloud.ibm.com/apidocs/iam-identity-token-api#gettoken-crtoken)
yourself.

Each of the samples then uses the token to list the files in a Cloud Object
Storage bucket.

Following are the steps to run the sample. Please note that the sample
requires account permissions to create various resources including those
related to IAM permissions.

## Setup

To setup the example, you need three things:

1. A Code Engine project
2. A Cloud Object Storage bucket
3. A trusted profile that grants access to the Cloud Object Storage bucket

### Creating a Code Engine project

We are using the command line interface here to setup things. If you have not
used it before, you can directly run it through the
[IBM Cloud shell](https://cloud.ibm.com/shell).

When running locally, make sure the necessary plugin is installed:

```sh
ibmcloud plugin install code-engine
```

In the IBM Cloud shell, the plugin is already installed, however it makes
sense to ensure the latest version is installed:

```sh
ibmcloud plugin update --all --force
```

Then you are ready to create a Code Engine project. Here and in the following
snippets, variables will be used. Feel free to adjust them to your needs, but
make sure that you use the same value for the same variable in all snippets.

```sh
REGION=eu-es
RESOURCE_GROUP=Default
CE_PROJECT_NAME=trusted-profiles-test

ibmcloud target -r ${REGION} -g ${RESOURCE_GROUP}
ibmcloud ce project create --name ${CE_PROJECT_NAME}
```

### Creating a Cloud Object Storage bucket

For this sample, you can use an existing Cloud Object Storage bucket that
you already have. If you never used COS, then here is a one-sentence
introduction: Cloud Object Storage is a managed data service where you can
store data in files.

With the following commands, you will setup your first COS instance and a
bucket. First, make sure the CLI plugin is installed:

```sh
ibmcloud plugin install cos
```

The COS bucket uses a random suffix (`31292`) because bucket names must
be unique across all IBM Cloud customers in a region. Make sure you use
your own random characters.

```sh
REGION=eu-es
RESOURCE_GROUP=Default
COS_INSTANCE_NAME=my-first-cos
COS_BUCKET=my-first-bucket-31292

ibmcloud resource service-instance-create ${COS_INSTANCE_NAME} cloud-object-storage standard global -g ${RESOURCE_GROUP} -d premium-global-deployment-iam
COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:')
ibmcloud cos config crn --crn ${COS_INSTANCE_ID} --force
ibmcloud cos bucket-create --bucket ${COS_BUCKET} --class smart --ibm-service-instance-id ${COS_INSTANCE_ID} --region ${REGION}
```

To have content in the bucket, let's store a sample text file:

```sh
echo Hello World >helloworld.txt
ibmcloud cos object-put --region ${REGION} --bucket ${COS_BUCKET} --key helloworld.txt --body helloworld.txt
```

### Creating a trusted profile that grants a Code Engine Job access to your COS bucket

In this step, we are creating a Trusted Profile which grants read access to
your COS bucket to a Job called `list-cos-files` in your Code Engine project.

The Job itself, we will create later.

```sh
REGION=eu-es
RESOURCE_GROUP=Default
COS_INSTANCE_NAME=my-first-cos
COS_BUCKET=my-first-bucket-31292
CE_PROJECT_NAME=trusted-profiles-test
JOB_NAME=list-cos-files
TRUSTED_PROFILE_NAME=code-engine-cos-access

CE_PROJECT_CRN=$(ibmcloud resource service-instance ${CE_PROJECT_NAME} --location ${REGION} -g ${RESOURCE_GROUP} --crn 2>/dev/null | grep ':codeengine:')
COS_INSTANCE_ID=$(ibmcloud resource service-instance ${COS_INSTANCE_NAME} --crn 2>/dev/null | grep ':cloud-object-storage:')

ibmcloud iam trusted-profile-create ${TRUSTED_PROFILE_NAME}
ibmcloud iam trusted-profile-link-create ${TRUSTED_PROFILE_NAME} --name ce-job-${JOB_NAME} --cr-type CE --link-crn ${CE_PROJECT_CRN} --link-component-type job --link-component-name ${JOB_NAME}
ibmcloud iam trusted-profile-policy-create ${TRUSTED_PROFILE_NAME} --roles "Content Reader" --service-name cloud-object-storage --service-instance ${COS_INSTANCE_ID} --resource-type bucket --resource ${COS_BUCKET}
```

## Running the sample

To run the sample, we will now create the Code Engine Job pointing to the
sources in this repository. Feel free to use `go`, `java`, `node` or
`python` as value for the `PROGRAMMING_LANGUAGE` variable.

```sh
REGION=eu-es
COS_BUCKET=my-first-bucket-31292
JOB_NAME=list-cos-files
PROGRAMMING_LANGUAGE=node
TRUSTED_PROFILE_NAME=code-engine-cos-access

ibmcloud ce job create --name ${JOB_NAME} \
--build-source https://github.com/IBM/CodeEngine \
--build-context-dir trusted-profiles/${PROGRAMMING_LANGUAGE} \
--trusted-profiles-enabled true \
--env COS_REGION=${REGION} \
--env COS_BUCKET=${COS_BUCKET} \
--env TRUSTED_PROFILE_NAME=${TRUSTED_PROFILE_NAME}
```

Code Engine will setup the Job and as part of that runs a build of the chosen
source. The output is a container image that it pushes to a Container Registry
namespace that it creates for your project. Once that completed, your Job is
ready to be run:

```sh
JOB_NAME=list-cos-files

ibmcloud ce jobrun submit --job ${JOB_NAME} --name ${JOB_NAME}-run-1
ibmcloud ce jobrun logs --name ${JOB_NAME}-run-1 --follow
```

If everything has been setup correctly, the JobRun logs will show the number
of items it found and their keys, in case you set up the sample bucket above,
then it will be just one item called helloworld.txt.

## Code Review

All of the four samples use the language-specific IBM Cloud SDK. Those define
an `Authenticator` interface and provide the `ContainerAuthenticator`
implementation. When instantiating the `ContainerAuthenticator`, you must
provide the identifier or name of trusted profile. The sample job from above
uses the name which is defined as `TRUSTED_PROFILE_NAME` environment variable
on the Code Engine Job.

The `Authenticator` has an `authenticate` method that augments an existing
HTTP request object with the necessary `Authorization` header. Under the
covers, the `ContainerAuthenticator` for that purpose reaches out to
[IAM to retrieve an access token for a compute resource token](https://cloud.ibm.com/apidocs/iam-identity-token-api#gettoken-crtoken).

The `ContainerAuthenticator` will also automatically manage the refresh of the
token.

The sample code authenticates a request against the Cloud Object Storage API
to list the items in a bucket. The response is parsed and printed.
15 changes: 15 additions & 0 deletions trusted-profiles/go/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# Env Vars:
# REGISTRY: name of the image registry/namespace to store the images
#
# NOTE: to run this you MUST set the REGISTRY environment variable to
# your own image registry/namespace otherwise the `docker push` commands
# will fail due to an auth failure. Which means, you also need to be logged
# into that registry before you run it.

set -ex
export REGISTRY=${REGISTRY:-icr.io/codeengine}

# Build and push the image
KO_DOCKER_REPO="${REGISTRY}/trusted-profiles/go" ko build . --bare --image-user 1001 --platform linux/amd64 --sbom=none
28 changes: 28 additions & 0 deletions trusted-profiles/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module github.com/IBM/CodeEngine/trusted-profiles/go

go 1.23.0

require github.com/IBM/go-sdk-core/v5 v5.19.0

require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/stretchr/testify v1.10.0 // indirect
go.mongodb.org/mongo-driver v1.17.3 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
77 changes: 77 additions & 0 deletions trusted-profiles/go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
github.com/IBM/go-sdk-core/v5 v5.19.0 h1:YN2S5JUvq/EwYulmcNFwgyYBxZhVWl9nkY22H7Hpghw=
github.com/IBM/go-sdk-core/v5 v5.19.0/go.mod h1:deZO1J5TSlU69bCnl/YV7nPxFZA2UEaup7cq/7ZTOgw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
77 changes: 77 additions & 0 deletions trusted-profiles/go/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"encoding/xml"
"fmt"
"io"
"log"
"net/http"
"os"

"github.com/IBM/go-sdk-core/v5/core"
)

type content struct {
Key string `xml:"Key"`
}

type listBucketResult struct {
Contents []content `xml:"Contents"`
}

func main() {
// read environment variables
cosBucket := os.Getenv("COS_BUCKET")
if cosBucket == "" {
log.Panic("environment variable COS_BUCKET is not set")
}
cosRegion := os.Getenv("COS_REGION")
if cosRegion == "" {
log.Panic("environment variable COS_REGION is not set")
}
trustedProfileName := os.Getenv("TRUSTED_PROFILE_NAME")
if trustedProfileName == "" {
log.Panic("environment variable TRUSTED_PROFILE_NAME is not set")
}

// create an authenticator based on a trusted profile
authenticator := core.NewContainerAuthenticatorBuilder().SetIAMProfileName(trustedProfileName)

// prepare the request to list the files in the bucket
request, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://s3.direct.%s.cloud-object-storage.appdomain.cloud/%s", cosRegion, cosBucket), nil)
if err != nil {
log.Panicf("Failed to create request: %v", err)
}

// authenticate the request
if err = authenticator.Authenticate(request); err != nil {
log.Panicf("Failed to authenticate request: %v", err)
}

// perform the request
response, err := http.DefaultClient.Do(request)
if err != nil {
log.Panicf("Failed to perform request: %v", err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
log.Panicf("Unexpected status code: %d", response.StatusCode)
}

body, err := io.ReadAll(response.Body)
if err != nil {
log.Panicf("Failed to read response body: %v", err)
}

// parse the response which is in XML format
listBucketResult := &listBucketResult{}
if err = xml.Unmarshal(body, listBucketResult); err != nil {
log.Panicf("Failed to parse response body: %v", err)
}

// print the details
log.Printf("Found %d objects:", len(listBucketResult.Contents))
for _, item := range listBucketResult.Contents {
log.Printf("- %s", item.Key)
}
}
5 changes: 5 additions & 0 deletions trusted-profiles/java/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.dockerignore
.gitignore
build
Dockerfile
target
1 change: 1 addition & 0 deletions trusted-profiles/java/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
Loading