Skip to content
Open
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
10 changes: 8 additions & 2 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ permissions:
contents: read

jobs:
shellcheck:
# The reusable workflow runs `find "$SCRIPT_DIRS"`, quoting the value as a
# single path — so a space-separated list breaks. Pass one path per job.
shellcheck-entrypoint:
uses: nullplatform/actions-nullplatform/.github/workflows/shellcheck.yml@main
with:
script_dirs: entrypoint scripts
script_dirs: entrypoint
shellcheck-scripts:
uses: nullplatform/actions-nullplatform/.github/workflows/shellcheck.yml@main
with:
script_dirs: scripts
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.idea

.DS_Store
.DS_Store

.env
.claude
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to `application-lifecycle-manager` will be documented in thi
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) once it reaches a stable API.

## [Unreleased]

### Added
- `CREATE_CODE_REPOSITORY` and `CREATE_ASSET_REPOSITORY` flags to toggle code and asset
repository creation independently.
- AWS ECR asset repository provider.

### Changed
- Migrated docker-server asset persistence from the deprecated `np nrn patch`
(`docker.repository_uri`) to `np application patch` (`settings.asset.docker_server.uri`).


## [0.2.0] - 2025-11-13

### Added
Expand Down
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The code repository workflow is composed of the following tasks:

You must configure your asset repository provider through **nullplatform platform settings** or the **nullplatform Terraform provider**.

> **Note:** At the moment, this repository supports **Docker Server** repositories only.
> **Note:** This repository supports **Docker Server** and **AWS ECR** asset repositories.

#### Workflow

Expand All @@ -79,6 +79,39 @@ The asset repository workflow is composed of the following tasks:
- **Create repository**
Creates a namespace/folder in your Docker registry for the new application and stores its location in the nullplatform API.

#### Using AWS ECR

To use AWS ECR as the asset repository provider, set `ASSET_REPOSITORY_PROVIDER=ecr` in the
agent environment along with:

| Variable | Required | Description |
|-----------------------|----------|-------------------------------------------------------------------|
| `AWS_REGION` | yes | Region where the ECR repository is created. |
| `ECR_REPOSITORY_PATH` | no | Optional prefix prepended to the repository name. |
| `ECR_USE_NAMESPACE` | no | When `true`, joins namespace and application with `/` instead of `-`. |

The generated repository name must satisfy ECR naming rules (lowercase, made up of `[a-z0-9._/-]`, no leading slash). Choose `ECR_REPOSITORY_PATH` and namespace/application slugs accordingly.

**Prerequisites:** the agent host must have the `aws` CLI installed and AWS credentials
available in its environment (for example, via IRSA on EKS). The bound IAM role needs
`ecr:CreateRepository` and `ecr:DescribeRepositories`. The repository URI and ARN are read
from the AWS API response and persisted to the application's `settings.asset.ecr`.

---

## Toggling repository creation

You can disable either side of the lifecycle independently with environment variables set
on the agent:

| Variable | Default | Effect |
|----------------------------|---------|-----------------------------------------------------|
| `CREATE_CODE_REPOSITORY` | enabled | Set to `false` to skip code repository creation. |
| `CREATE_ASSET_REPOSITORY` | enabled | Set to `false` to skip asset repository creation. |

Any value other than `false` (case-insensitive), including unset, keeps the default
behavior of creating the repository.

---

## Installing the application lifecycle manager
Expand Down
5 changes: 5 additions & 0 deletions scripts/asset-repo/create_asset_repository
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/bin/bash

if [[ "${CREATE_ASSET_REPOSITORY,,}" == "false" ]]; then
echo "CREATE_ASSET_REPOSITORY=false — skipping asset repository creation"
return 0
fi

ASSET_REPOSITORY=$(np provider list --categories assets-repository --nrn "$NRN" --format json | jq ".results[0]")

if [[ -n "$ASSET_REPOSITORY_PROVIDER" ]]; then
Expand Down
6 changes: 5 additions & 1 deletion scripts/asset-repo/docker-server/create_repository
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#!/bin/bash

np nrn patch --nrn "$NRN" --body "{\"docker.repository_uri\":\"$DOCKER_SERVER_URI\"}"
BODY=$(jq -n \
--arg uri "$DOCKER_SERVER_URI" \
'{settings: {asset: {docker_server: {uri: $uri}}}}')

np application patch --id "$APPLICATION_ID" --body "$BODY"
12 changes: 12 additions & 0 deletions scripts/asset-repo/ecr/build_context
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

if [[ -z "$AWS_REGION" ]]; then
echo "ERROR: AWS_REGION is required for the ECR asset provider but is not set."
exit 1
fi

echo "Using AWS_REGION: $AWS_REGION"

export AWS_REGION
export ECR_REPOSITORY_PATH
export ECR_USE_NAMESPACE
53 changes: 53 additions & 0 deletions scripts/asset-repo/ecr/create_repository
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash

echo "Creating ECR repository: $ECR_REPOSITORY_NAME in region $AWS_REGION"

CREATE_OUTPUT=$(aws ecr create-repository \
--repository-name "$ECR_REPOSITORY_NAME" \
--region "$AWS_REGION" \
--output json 2>&1)
CREATE_STATUS=$?

if [[ $CREATE_STATUS -eq 0 ]]; then
REPOSITORY=$(echo "$CREATE_OUTPUT" | jq '.repository')
elif echo "$CREATE_OUTPUT" | grep -q "RepositoryAlreadyExistsException"; then
echo "ECR repository already exists, fetching its details"
DESCRIBE_OUTPUT=$(aws ecr describe-repositories \
--repository-names "$ECR_REPOSITORY_NAME" \
--region "$AWS_REGION" \
--output json 2>&1)
DESCRIBE_STATUS=$?
if [[ $DESCRIBE_STATUS -ne 0 ]]; then
echo "ERROR: failed to describe existing ECR repository:"
echo "$DESCRIBE_OUTPUT"
exit 1
fi
REPOSITORY=$(echo "$DESCRIBE_OUTPUT" | jq '.repositories[0]')
else
echo "ERROR: failed to create ECR repository:"
echo "$CREATE_OUTPUT"
exit 1
fi

ECR_REPOSITORY_URI=$(echo "$REPOSITORY" | jq -r '.repositoryUri')
ECR_REPOSITORY_ARN=$(echo "$REPOSITORY" | jq -r '.repositoryArn')

if [[ -z "$ECR_REPOSITORY_URI" || "$ECR_REPOSITORY_URI" == "null" ]]; then
echo "ERROR: could not resolve ECR repository URI from AWS response."
exit 1
fi

if [[ -z "$ECR_REPOSITORY_ARN" || "$ECR_REPOSITORY_ARN" == "null" ]]; then
echo "ERROR: could not resolve ECR repository ARN from AWS response."
exit 1
fi

echo "ECR repository URI: $ECR_REPOSITORY_URI"
echo "ECR repository ARN: $ECR_REPOSITORY_ARN"

BODY=$(jq -n \
--arg uri "$ECR_REPOSITORY_URI" \
--arg arn "$ECR_REPOSITORY_ARN" \
'{settings: {asset: {ecr: {uri: $uri, arn: $arn}}}}')

np application patch --id "$APPLICATION_ID" --body "$BODY"
18 changes: 18 additions & 0 deletions scripts/asset-repo/ecr/generate_repository_uri
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash

ECR_REPOSITORY_NAME=""

if [[ -n "$ECR_REPOSITORY_PATH" ]]; then
ECR_REPOSITORY_NAME="$ECR_REPOSITORY_PATH/"
fi

SEPARATOR="-"
if [[ "$ECR_USE_NAMESPACE" == "true" ]]; then
SEPARATOR="/"
fi

ECR_REPOSITORY_NAME="${ECR_REPOSITORY_NAME}${NAMESPACE_SLUG}${SEPARATOR}${APPLICATION_SLUG}"

echo "ECR repository name: $ECR_REPOSITORY_NAME"

export ECR_REPOSITORY_NAME
5 changes: 5 additions & 0 deletions scripts/code-repo/create_code_repository
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/bin/bash

if [[ "${CREATE_CODE_REPOSITORY,,}" == "false" ]]; then
echo "CREATE_CODE_REPOSITORY=false — skipping code repository creation"
return 0
fi

CURRENT_DIR=$(dirname "${BASH_SOURCE[0]}")

REPOSITORY_URL=$(echo "$APPLICATION" | jq -r .repository_url)
Expand Down