# Harbor Tag Retention Policy

This document describes the recommended tag retention policy for the Mosaic Stack container images in Harbor.

## Tagging Strategy

Images are tagged based on branch and event type:

| Trigger           | Tags Applied      | Example              |
| ----------------- | ----------------- | -------------------- |
| Push to `main`    | `{sha}`, `latest` | `658ec077`, `latest` |
| Push to `develop` | `{sha}`, `dev`    | `a1b2c3d4`, `dev`    |
| Git tag (release) | `{sha}`, `{tag}`  | `658ec077`, `v1.0.0` |

### Tag Meanings

| Tag                        | Purpose                                    | Stability |
| -------------------------- | ------------------------------------------ | --------- |
| `latest`                   | Current production-ready build from `main` | Stable    |
| `dev`                      | Current development build from `develop`   | Unstable  |
| `v*` (e.g., `v1.0.0`)      | Versioned release                          | Immutable |
| `{sha}` (e.g., `658ec077`) | Specific commit for traceability           | Immutable |

## Retention Policy Configuration

Configure in Harbor UI: **Projects → mosaic → Policy → Tag Retention**

### Recommended Rules

Create the following retention rules in order:

#### Rule 1: Keep Release Tags Forever

```
Repositories: **
Tag filter: v*
Retain: all
```

Keeps all versioned releases (v1.0.0, v2.0.0, etc.)

#### Rule 2: Keep Latest and Dev Tags

```
Repositories: **
Tag filter: {latest,dev}
Retain: all
```

Keeps the `latest` and `dev` tags (always exactly one of each)

#### Rule 3: Keep Recent SHA Tags

```
Repositories: **
Tag filter: *
Retain: most recent 10 tags
```

Keeps the 10 most recent commit SHA tags for rollback capability

### Expected Result

After retention runs:

- All `v*` tags preserved
- `latest` and `dev` tags preserved
- Last 10 SHA tags preserved
- Older SHA tags deleted

## Garbage Collection

Tag retention only removes tag references. Actual blob storage is reclaimed via garbage collection.

### Schedule GC

**Harbor UI:** Administration → Garbage Collection

Recommended schedule: **Weekly** (Sunday 2:00 AM)

Options:

- ☑ Delete untagged artifacts (removes images with no tags)
- Workers: 1 (adjust based on registry size)

### Manual GC

Run on-demand after large cleanup operations:

1. Go to Administration → Garbage Collection
2. Click "GC Now"
3. Monitor job status

## Cleanup Commands

### Delete Specific Tag (API)

```bash
# Delete a specific tag
curl -sk -X DELETE -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/api/artifacts/{tag}"

# Example: delete old test tag
curl -sk -X DELETE -u "robot\$woodpecker-ci:$TOKEN" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/api/artifacts/test"
```

### List All Tags

```bash
# List tags for a repository
curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/v2/mosaic/api/tags/list" | jq '.tags'
```

### Bulk Delete Old SHA Tags (Script)

```bash
#!/bin/bash
# Delete SHA tags older than the 10 most recent
HARBOR_AUTH="robot\$woodpecker-ci:$TOKEN"
REPO="mosaic/api"

# Get all SHA tags (8 char hex), sorted by push time
TAGS=$(curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/${REPO#mosaic/}/artifacts?with_tag=true" | \
  jq -r 'sort_by(.push_time) | .[:-10] | .[].tags[]?.name | select(test("^[a-f0-9]{8}$"))')

for tag in $TAGS; do
  echo "Deleting $REPO:$tag"
  curl -sk -X DELETE -u "$HARBOR_AUTH" \
    "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/${REPO#mosaic/}/artifacts/$tag"
done
```

## Monitoring

### Check Repository Size

```bash
curl -sk -u "$HARBOR_AUTH" \
  "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic" | \
  jq '{name, repo_count, chart_count}'
```

### Check Artifact Count Per Repository

```bash
for repo in api web postgres; do
  count=$(curl -sk -u "$HARBOR_AUTH" \
    "https://reg.mosaicstack.dev/api/v2.0/projects/mosaic/repositories/$repo/artifacts" | jq 'length')
  echo "$repo: $count artifacts"
done
```

## Best Practices

1. **Never delete `latest` or `dev` manually** - CI will recreate them on next push
2. **Don't delete release tags (`v*`)** - These should be preserved for rollbacks
3. **Run GC after bulk deletions** - Reclaim storage space
4. **Monitor storage usage** - Set up alerts if approaching quota
5. **Test retention policy** - Use "Dry Run" option before enabling

## Related Documentation

- [Woodpecker-Harbor Integration Tips](../docs/work/woodpecker-harbor-integration-tips.md) (in jarvis-brain)
- [Harbor Official Docs: Tag Retention](https://goharbor.io/docs/2.0.0/administration/tag-retention/)
