Skip to content

feat(harbor): build the Harbor images for amd64 and arm64 - #4528

Closed
Aleksei Sviridkin (lexfrei) wants to merge 1 commit into
mainfrom
feat/harbor-multiarch
Closed

Aleksei Sviridkin (lexfrei) wants to merge 1 commit into
mainfrom
feat/harbor-multiarch

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

The Harbor app can't run on arm64 nodes: every Harbor pod crash-loops with exec format error. Upstream publishes the v2.15 component images for amd64 only. That covers v2.15.1, which the vendored chart pins, and every v2.15.x release and candidate up to v2.15.3-rc2.

Upstream's multi-arch build landed on main in goharbor/harbor#22311. It lives in CI workflows and native per-arch runners rather than in the Dockerfiles, and it has not been backported to release-2.15.0. The first release expected to carry arm64 is 2.16, planned for late October.

Until then this package rebuilds the pinned v2.15.1 release itself, for amd64 and arm64:

  • images/harbor/Dockerfile has one --target per image: harbor-core, harbor-jobservice, harbor-registryctl, harbor-exporter, registry-photon, nginx-photon and trivy-adapter-photon. The Go components cross-compile on the build platform. The registry builds from goharbor/distribution and the scanner from harbor-scanner-trivy, at the tags upstream's Makefile pins. The Trivy binary is downloaded per architecture and checked against the release checksums. Every source clone asserts its commit.
  • images/harbor-portal/Dockerfile builds the Angular portal. It is a separate file because its output is static JS, so the cross-compile check lists it as architecture-neutral. It takes the release pin from the main Dockerfile, so both files build the same commit.
  • The runtime images keep upstream's layout: the multi-arch goharbor/photon:5.0 base (pinned by index digest), uid 10000, the same paths and entrypoints.
  • make image builds all eight and stamps <registry>/<name>:<tag>@<digest> into the chart's harbor.<component>.image overrides in values.yaml. The package joins the root build: list. Until CI stamps them, the committed refs point at the upstream v2.15.1 digests.

I checked it on an arm64 cluster: a separate Harbor instance on the rebuilt images came up with every component healthy in /api/v2.0/health. It reported v2.15.1-335c05f2. Pushing and pulling a multi-arch image through it round-tripped the digest, a Trivy scan finished successfully, and the exporter served metrics. Each image is an amd64+arm64 index, and the binaries are the right ELF architecture in each variant.

The vendored chart is now pinned too. make update used to fetch the latest chart, while values.yaml pins the images to v2.15.1, so a chart bump would silently run a new chart on old images. The Makefile pins HARBOR_CHART_VERSION = 1.19.1 (whose appVersion is 2.15.1), and make update fails if the fetched chart's appVersion differs from HARBOR_VERSION.

One difference from upstream's images: upstream links the Go binaries dynamically with cgo, while these are built with CGO_ENABLED=0. Harbor's code has no import "C", and everything above ran on the static binaries.

These are eight new first-party images. Their e2e registry repos may come up private on the first push, which shows up as a 403 on pull, not as a code problem.

The source stage checks the pins against upstream's Makefile at the pinned tag: registry, distribution, trivy and swagger, plus the golang and node build images, which it compares with the version the running image actually reports. A Harbor bump that forgets one of them fails the build instead of shipping mismatched components. A Renovate rule stops tag bumps of the build base images under packages/system/harbor/images/**, since even a patch bump moves the build off upstream's toolchain; digest updates still come through.

When the vendored chart moves to a multi-arch upstream release, all of this can be deleted: both Dockerfiles, the image target, the values.yaml overrides, the root build: line, the portal's architecture-neutral entry, the Renovate rule and the appVersion check in make update. The Dockerfiles say so in their headers.

This PR only builds the images. CI publishes the arm64 variant once the multi-arch pre-release build (#4505) is in place, so #4520 stays open until a release carries it.

Screenshots

Not a UI change.

Downstream repositories

Release note

feat(harbor): The Harbor application now runs on arm64 nodes. Its component images are rebuilt from the pinned upstream v2.15.1 release for amd64 and arm64, because upstream publishes v2.15 images for amd64 only.

Summary by CodeRabbit

  • New Features
    • Harbor v2.15.1 is now packaged with rebuilt images for its core services and portal, enabling multi-architecture deployment.
    • Harbor image references are pinned to specific versions and digests for more consistent deployments.
  • Improvements
    • The main build command now includes building the Harbor images.

@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: cozystack/cozystack/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 0a691e47-83b5-41c0-bf52-a133dae2877a

📥 Commits

Reviewing files that changed from the base of the PR and between 6d759cc and 11991b9.

📒 Files selected for processing (7)
  • .github/renovate.json
  • Makefile
  • hack/image-builders-cross-compile.bats
  • packages/system/harbor/Makefile
  • packages/system/harbor/images/harbor-portal/Dockerfile
  • packages/system/harbor/images/harbor/Dockerfile
  • packages/system/harbor/values.yaml

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds Harbor v2.15.1 image builds, pins the Harbor chart to version 1.19.1, and connects the build to the repository’s build target. It adds backend and portal Dockerfiles, updates image references with built digests, and adjusts Renovate and architecture-neutral image-builder settings.

Changes

Harbor image builds

Layer / File(s) Summary
Pin and wire Harbor image builds
.github/renovate.json, Makefile, packages/system/harbor/Makefile, packages/system/harbor/values.yaml
Pins the chart release and checks its app version against the Harbor version. Defines the eight image targets and updates values.yaml with each built image’s repository, tag, and digest. The root build target invokes the Harbor image target. Renovate disables version updates for the Harbor Dockerfiles while leaving digest updates available.
Build Harbor backend components
packages/system/harbor/images/harbor/Dockerfile
Pins Harbor source and dependencies, checks dependency and toolchain versions, and builds the backend components, registry, and Trivy adapter. The Trivy download checks architecture-specific checksums and rejects unsupported architectures.
Package Harbor runtime images
packages/system/harbor/images/harbor/Dockerfile
Adds Photon runtime images for Harbor components, with component-specific binaries, users, entrypoints, volumes, and commands.
Build the Harbor portal image
packages/system/harbor/images/harbor-portal/Dockerfile, hack/image-builders-cross-compile.bats
Builds the portal and Swagger UI, packages their assets with nginx, and adds the portal Dockerfile to the architecture-neutral list.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant RootMake as Root Makefile
  participant HarborMake as Harbor Makefile
  participant DockerBuild as Docker build
  participant Values as values.yaml
  RootMake->>HarborMake: invoke image target
  HarborMake->>DockerBuild: build image and write metadata
  DockerBuild-->>HarborMake: return metadata with image digest
  HarborMake->>Values: update repository, tag, and digest
Loading

Merge Risk: ⚪ Minimal · up to 11991

No actionable merge-blocking issue is established. The image references and portal asset paths align with their consumers; normal build checks remain appropriate.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 11991

The new image pipeline affects the whole Harbor installation. Source revisions, downloads, and deployed image references have several explicit integrity controls, but the reviewed evidence does not establish that the published images support arm64 or that every runtime path has been validated.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — An erroneous or compromised published image could affect the Harbor installation’s artifact-serving components and vulnerability scanner. The evidence does not establish exposure across other installations, tenants, or environments.

Trust Boundaries and Controls

  • observed — The build crosses from externally obtained source and downloads into published runtime images. Commit assertions, pinned base-image digests, a Trivy checksum check, digest-qualified chart references, and non-root runtime users are visible controls; no bypass of an authentication or authorization boundary was established.

Resilience and Maintainability Implications

  • inferred — Image-set consistency matters to Harbor’s registry and scanning functions. The reviewed PR workflow prevents a failed package build from reaching its final packaging step, but the evidence does not establish an arm64 manifest check before production publication.

Hardening Proposals

  • proposed — Before promoting a replacement image set, verify that every recorded digest resolves for both amd64 and arm64 and that the eight references are published together. This addresses a rollout proof gap, not an established bypass in the reviewed PR workflow.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: building Harbor images for amd64 and arm64.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files labels Sep 27, 2026
@lexfrei
Aleksei Sviridkin (lexfrei) force-pushed the feat/harbor-multiarch branch 2 times, most recently from 2255fe9 to 4ce33f9 Compare September 27, 2026 15:12
@lexfrei
Aleksei Sviridkin (lexfrei) marked this pull request as ready for review September 27, 2026 15:32
@lexfrei
Aleksei Sviridkin (lexfrei) force-pushed the feat/harbor-multiarch branch 2 times, most recently from 2ee20f7 to 227ebab Compare September 27, 2026 22:30
Upstream publishes the Harbor v2.15 component images for amd64 only,
so every Harbor pod crash-loops with "exec format error" on an arm64
node. The multi-arch build upstream exists on main but is in no
release yet, so the package now rebuilds the pinned v2.15.1 release
itself: the Go components cross-compile on the build platform, the
registry and the Trivy adapter build from the tags upstream's Makefile
pins, the Trivy binary is fetched per architecture against its release
checksum, and the runtime images keep upstream's photon base, users
and entrypoints. The build fails when those registry and Trivy pins,
the swagger generator or the golang and node build images no longer
match upstream's Makefile at the pinned release, so a version bump
cannot pair a new core with an old registry, scanner or toolchain.

The portal compiles to static JS, so it lives in its own Dockerfile
listed as architecture-neutral in the cross-compile check, and takes
the release pin from the main one so both files build the same
commit.

Because values.yaml now pins the images, `make update` pins the chart
release that ships the same Harbor version and fails when its
appVersion differs, instead of pulling the newest chart onto old
images. Renovate stops proposing tag bumps for the rebuild's build
bases, which follow upstream's toolchain for that release.

The committed refs stay on the upstream digests until CI stamps the
rebuilt ones.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
IvanHunters
IvanHunters previously approved these changes Sep 28, 2026

@IvanHunters IvanHunters left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed statically in a hermetic clone. Confirmed all eight Harbor images route through the shared multi-arch buildx flags, cross-checked every base image, pin, digest and Trivy checksum against upstream v2.15.1, and confirmed the internal amd64-only db and redis StatefulSets never deploy (the chart forces external CNPG and RedisFailover). LGTM.

@lexfrei

Copy link
Copy Markdown
Contributor Author

Superseded by #4552, which carries this change together with #4507, #4515 and #4525, so the four can be approved once. The conflict with main is resolved there.

Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Sep 28, 2026
…unlisted images for arm64 (#4552)

## What this PR does

This brings together four approved PRs that give the remaining
first-party images an arm64 build. Each of them lost its approval when
#4498 merged and GitHub retargeted it to main, so I merged them into one
branch to review and approve once. Each original PR has the full
description and review history, and I'll close them in favour of this
one.

- #4507 builds the Talos installer and matchbox for arm64. Releases also
publish the arm64 ISO, disk images, kernel and initramfs.
- #4515 builds the KubeVirt Velero plugin in-tree for amd64 and arm64.
- #4525 adds flux-plunger, keycloak-operator, kilo and
migration-controller to the root `build:` list, so CI rebuilds them like
every other image. A test keeps any new image target from being left
out.
- #4528 rebuilds the Harbor v2.15.1 images for amd64 and arm64, because
upstream publishes v2.15 for amd64 only.

Release builds still run with `PLATFORM=linux/amd64`, except the Talos
installer, so these images ship arm64 only once #4505 adds the arm64
leg. This PR makes that leg buildable.

A few commits are new on top of the originals. The velero test no longer
pins the plugin's image string, because the release build stamps its own
rebuild over it. It now checks the plugin init container by repository
name. A promote-retag test comment now says what it guards, and the
image-refs doc no longer calls its fixed gaps open. The merge with main
keeps the Harbor portal in the list of stages whose output has no
architecture.

### Screenshots

Not a UI change.

### Downstream repositories

I left every box empty and opened nothing in other repositories. Two
repositories are touched, and neither follow-up is needed before this
merges:

- cozystack/website names the amd64 assets in
`content/en/docs/next/install/talos/iso.md` and
`install/providers/oracle-cloud.md`. The install pages could offer the
arm64 downloads once a release carries them. No asset is renamed, so the
current links keep working.
- cozystack/talm points at `ghcr.io/cozystack/cozystack/talos:<version>`
in `charts/cozystack/values.yaml`. Once a release publishes that tag as
a two-arch index, the same reference works on arm64 nodes, so nothing
there has to change.

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
feat(talos): the Talos installer image is built for amd64 and arm64, with arm64 profiles that carry drbd and zfs, and the bootbox matchbox image network-boots arm64 machines as well as amd64 ones. Releases publish the arm64 Talos ISO, disk images, kernel and initramfs.
feat(velero): the KubeVirt Velero plugin is now built in-tree for amd64 and arm64, so the velero server starts on arm64 clusters.
build: flux-plunger, keycloak-operator, kilo and migration-controller are now rebuilt by CI like every other first-party image, so their pinned images pick up source patches and base-image updates and are published for amd64 and arm64.
feat(harbor): the Harbor application now runs on arm64 nodes. Its component images are rebuilt from the pinned upstream v2.15.1 release for amd64 and arm64, because upstream publishes v2.15 images for amd64 only.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Talos images and boot assets now support both AMD64 and ARM64,
including architecture-specific installation and cloud images.
* Added build support for Harbor components and the KubeVirt Velero
plugin.
  * Nightly builds now include ARM64 release assets.
* **Improvements**
* Harbor uses pinned chart and image versions, with built image
references recorded automatically.
* Added checks to catch image packages missing from the main build and
to verify multi-architecture installer output.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Aleksei Sviridkin (lexfrei) added a commit that referenced this pull request Sep 29, 2026
…leases on it (#4505)

## What this PR does

Pre-release builds now publish every image as an amd64 and arm64 index,
and a release fails if anything it ships is single-arch. Main, release
lines and pull requests keep building amd64 only. It builds on #4498,
which made every image buildable for both architectures. Part of #1961.

**This PR is on hold until everything under "Merge after" has landed.**
Merged earlier, the new gate fails the next rc on the images those PRs
fix.

### How a pre-release is built

A pre-release tag gets a second job, for arm64, next to the existing
release job. That covers `-rc.N`, `-beta.N` and `-alpha.N` tags. It runs
on the CNCF arm64 pool (`oracle-vm-24cpu-96gb-arm64`), builds the same
images with `PLATFORM=linux/arm64`, and pushes them as `<tag>-arm64`.
`prepare-release` waits for it, and if the arm64 job fails the rc fails
with it. There is no amd64-only fallback. Stable tags do not run it:
promotion copies the rc digests with `skopeo copy --multi-arch all`, so
a stable release inherits the indexes.

After the amd64 build, the stitch joins each amd64 image with its arm64
twin into one index. It lives in `hack/stitch-multiarch.sh`. Every tag
of the amd64 image moves to the index, the component-versioned ones
included. The script then rewrites the digests in the tree and
republishes the packages artifact and the installer chart pinned on
them. It reads refs through `hack/lib/image-refs.sh`, and it fails if an
old digest survives anywhere outside `charts/`.

### The gate

A new check fails the rc when a pinned digest in the tree is not an
index with both linux/amd64 and linux/arm64. It lives in
`hack/verify-multiarch.sh`. It checks first-party and third-party refs
alike. Images that are amd64 by nature go into
`hack/multiarch-allowlist`, one repository per line, each with a
mandatory reason. Today that is only the e2e sandbox. An entry that
matches nothing is reported as stale.

The static gate only sees digest-pinned refs in the tree. A tag-only
ref, an image from a vendored chart default, or one an operator starts
at runtime is invisible to it. So the rc e2e also audits every image its
nodes pulled, with the same check and the same allowlist. Neither covers
a package the e2e never installs.

### Nightly

A new nightly workflow builds main for arm64. It keeps the arm64 build
cache warm, since the rc job only reads it. It also prints the
single-arch refs that would block the next rc. Nothing it builds is
published.

### Smaller changes

- `CACHE_TAG` in `hack/common-envs.mk` moves the default cache ref, so
the arm64 build keeps a cache of its own.
- `MATRIX_ARCH=arm64` makes `hack/build-matrix.sh` leave out the
amd64-only e2e sandbox.
- The kamaji provider image is pushed under the build's `IMAGE_TAG` like
every other image. Its Makefile set `IMAGE_TAG` itself, so concurrent
builds overwrote each other's component tag. Closes #4503.
- `hack/nightly-mirror.sh` verifies a copy against the raw manifest
digest. Plain `skopeo inspect` resolves an index to one platform's
child.
- matchbox is rebuilt for both platforms in the amd64 release job. The
arm64 leg skips the talos package, so there is no arm64 half to stitch,
and its Dockerfile only copies files, so no QEMU is needed. Releases
then network-boot arm64 machines too. Closes #4524.

The stitch also rewrites the kamaji ref inside `files/components.gz`,
recompressed with `gzip -n` so the bytes are reproducible, so the kamaji
control-plane provider ships multi-arch too. keda and kuberture now name
the repository next to their pinned digest, so the gate can resolve
them; their rendered manifests do not change.

### Merge after

- #4552 builds the Talos installer, matchbox, Harbor and the Velero
KubeVirt plugin for arm64, and adds flux-plunger, keycloak-operator,
kilo and migration-controller to the root `build:` list. It replaces
#4507, #4515, #4525 and #4528.
- #4549 moves ingress-nginx, cozy-proxy, cozystack-scheduler and
keycloak-kms-proxy to their multi-arch releases, which are already
published.

The rest of the stack is merged: #4485, #4498, #4512, #4517, #4521 and
#4522 here, and the multi-arch PRs in
ingress-nginx-with-protobuf-exporter, cozy-proxy, cozystack-scheduler
and keycloak-kms-proxy.

### Verification

The bats suites pass: stitch, verify-multiarch, build-matrix,
common-envs, nightly-mirror and the release contracts. The first three
also pass under `hack/cozytest.sh` with dash. Each new test was red
before its implementation, and the verify-multiarch and stitch tests
each have a mutation that turns them red. I ran `verify-multiarch
--report` against main. It lists the first-party refs the stitch will
fix, plus the third-party and special cases above. The workflows have
not run yet. The arm64 job's tools and duration, the stitch against real
registries, and the audit are checked for the first time on the nightly
and on the next rc.

### Screenshots

Not a UI change.

### Downstream repositories

- [x] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

Nothing under `hack/` is moved or renamed, and no make target changes
its default behaviour: `CACHE_TAG` and `MATRIX_ARCH` are opt-in. The
satellite repositories listed under "Merge after" are prerequisites, not
follow-ups this change forces on them.

### Release note

```release-note
ci(release): pre-release builds publish every image as an amd64 and arm64 multi-arch index, and a release fails if any image it ships or pulls in e2e lacks either architecture. Stable releases inherit the indexes through promotion.
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Release candidates now build amd64 and arm64 images in parallel and
combine eligible images into verified multi-architecture indexes before
publication.
* A nightly arm64 image build is available for testing and supplies a
build cache for release-candidate builds.
* **Bug Fixes**
* End-to-end checks audit whether pulled images support both
architectures. Audit failures block prerelease checks, while stable
releases continue with a warning.
* End-to-end test artifacts now include collected image references and
multi-architecture audit results.
* **Documentation**
* Updated release and image guidance covers multi-architecture builds,
verification checks, and troubleshooting, including arm64 build and
stitching failures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/storage Issues or PRs related to storage (linstor, seaweedfs, bucket, velero, harbor) kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants