Reputation: 11129
There are dozens of Q/A in Stack Overflow. I've applied all the solutions out there, but I keep getting the same error:
Cannot perform an interactive login from a non TTY device
For context:
I'm using Pulumi in GitHub Actions to deploy to GCP's Artifact Registry. I have two docker containers, and this is my yaml:
name: Deploy to Staging
on:
push:
branches:
- main
permissions:
actions: read
contents: read
id-token: write
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build affected apps
run: pnpm exec nx affected -t build
deploy:
runs-on: ubuntu-latest
environment: staging
needs: [ci]
steps:
- uses: actions/checkout@v4
- name: Create .env file
run: |
cat << EOF > libs/infrastructure/src/pulumi/.env
PULUMI_MAIN_SERVICE_ACCOUNT_STAGING="${{ secrets.PULUMI_MAIN_SERVICE_ACCOUNT_STAGING }}"
PULUMI_WORKLOAD_IDENTITY_PROVIDER_ID_STAGING="${{ secrets.PULUMI_WORKLOAD_IDENTITY_PROVIDER_ID_STAGING }}"
PULUMI_DOPPLER_REMIX_PROJECT="remix-app"
PULUMI_DOPPLER_REMIX_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_REMIX_STAGING_TOKEN }}"
PULUMI_DOPPLER_REMIX_STAGING_BRANCH_NAME="stg"
PULUMI_DOPPLER_TEMPORAL_PROJECT="temporal-worker"
PULUMI_DOPPLER_TEMPORAL_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_TEMPORAL_STAGING_TOKEN }}"
PULUMI_DOPPLER_TEMPORAL_STAGING_BRANCH_NAME="stg"
PULUMI_DOPPLER_CLOUD_RUN_REMIX_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_CLOUD_RUN_REMIX_STAGING_TOKEN }}"
PULUMI_DOPPLER_CLOUD_RUN_TEMPORAL_STAGING_TOKEN="${{ secrets.PULUMI_DOPPLER_CLOUD_RUN_TEMPORAL_STAGING_TOKEN }}"
EOF
- name: Configure Workload Identity Federation
id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.GCP_STAGING_WORKLOAD_IDENTITY_PROVIDER_ID }}
project_id: ${{ secrets.GCP_STAGING_PROJECT_ID }}
service_account: [email protected]
token_format: 'access_token'
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Configure Docker for Artifact Registry
run: |
gcloud auth configure-docker us-east1-docker.pkg.dev
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Artifact Registry
uses: docker/login-action@v3
with:
registry: us-east1-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
- name: Run Pulumi
uses: pulumi/actions@v6
with:
work-dir: 'libs/infrastructure/src/pulumi'
command: 'up'
stack-name: 'alertdown/alertdown-infra/dev'
comment-on-pr: true
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
Here's my infrastructure code:
package cloudrun
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/pulumi/pulumi-docker/sdk/v3/go/docker"
"github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp"
"github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp/artifactregistry"
"github.com/pulumi/pulumi-gcp/sdk/v8/go/gcp/projects"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type createArtifactRegistryNewRepositoryInput struct {
ctx *pulumi.Context
artifactRegistryRepoName string
artifactRegistryRepoLocation string
artifactRegistryService *projects.Service `pulumi:"artifactRegistryService"`
provider *gcp.Provider
}
func createArtifactRegistryNewRepository(input *createArtifactRegistryNewRepositoryInput) (*artifactregistry.Repository, error) {
if input.artifactRegistryService == nil {
return nil, errors.New("artifactRegistryService cannot be nil")
}
dependingResources := []pulumi.Resource{
input.artifactRegistryService,
}
repo, err := artifactregistry.NewRepository(input.ctx, input.artifactRegistryRepoName, &artifactregistry.RepositoryArgs{
Location: pulumi.String(input.artifactRegistryRepoLocation),
RepositoryId: pulumi.String(input.artifactRegistryRepoName),
Format: pulumi.String("DOCKER"),
Description: pulumi.String("The repository that will hold social-log Docker images."),
}, pulumi.DependsOn(dependingResources), pulumi.Provider(input.provider))
if err != nil {
return nil, err
}
return repo, nil
}
type buildAndPushToArtifactRegistryInput struct {
ctx *pulumi.Context
artifactRegistryRepo *artifactregistry.Repository
dockerImageName string
dockerImagePath string
dockerfileName string
provider *gcp.Provider
}
func buildAndPushToArtifactRegistry(input *buildAndPushToArtifactRegistryInput) (*docker.Image, error) {
if input.artifactRegistryRepo == nil {
return nil, errors.New("artifactRegistryRepo cannot be nil")
}
dependingSources := []pulumi.Resource{
input.artifactRegistryRepo,
}
// Get the absolute path to the project root
workingDir, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("failed to get working directory: %w", err)
}
// Go up to the project root (from /libs/infrastructure/src/pulumi)
projectRoot := filepath.Join(workingDir, "../../../../")
projectRoot, err = filepath.Abs(projectRoot)
if err != nil {
return nil, fmt.Errorf("failed to get absolute path: %w", err)
}
// Construct the absolute path to the Dockerfile
dockerfilePath := filepath.Join(projectRoot, "apps", input.dockerImagePath)
// Verify the Dockerfile exists
if _, err := os.Stat(dockerfilePath); os.IsNotExist(err) {
return nil, fmt.Errorf("dockerfile not found at path: %s", dockerfilePath)
}
// Create Docker build args using absolute paths
buildArgs := &docker.DockerBuildArgs{
Context: pulumi.String(dockerfilePath),
ExtraOptions: pulumi.StringArray{
pulumi.String("--platform=linux/amd64"),
pulumi.String("--build-context"),
pulumi.String(fmt.Sprintf("root=%v", projectRoot)),
},
Target: pulumi.String("production"),
}
// Construct the full image name with registry URL
// Format: LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE
registryUrl := pulumi.Sprintf("%s-docker.pkg.dev/%s/%s/%s",
input.artifactRegistryRepo.Location,
input.artifactRegistryRepo.Project,
input.artifactRegistryRepo.RepositoryId,
input.dockerImageName,
)
accessToken := os.Getenv("GOOGLE_ACCESS_TOKEN_FROM_CLI")
image, err := docker.NewImage(input.ctx, input.dockerImageName, &docker.ImageArgs{
Build: buildArgs,
ImageName: registryUrl, // Use the full registry URL instead of just the image name
Registry: &docker.ImageRegistryArgs{
Server: pulumi.Sprintf("%s-docker.pkg.dev", input.artifactRegistryRepo.Location),
Username: pulumi.String("oauth2accesstoken"),
Password: pulumi.String(accessToken), // Replace with a valid access token
},
}, pulumi.DependsOn(dependingSources), pulumi.Provider(input.provider))
if err != nil {
return nil, fmt.Errorf("failed to create docker image: %w", err)
}
Return image, nil
}
This code works locally.
I've also checked that the service account has the right permissions and roles.
Note that I'm using Workload Identity Federation.
Any ideas?
Upvotes: 0
Views: 40