From 78e78f9be7fac36d746029386b74ac92606de24c Mon Sep 17 00:00:00 2001 From: "osac-jira-ai-issue-solver[bot]" <280426608+osac-jira-ai-issue-solver[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:37:12 +0000 Subject: [PATCH 1/4] OSAC-1316: osac get publicips fails: CEL references removed compute_instance field Co-authored-by: osac-dev-bot --- proto/private/osac/private/v1/public_ips_service.proto | 2 +- proto/public/osac/public/v1/public_ips_service.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/private/osac/private/v1/public_ips_service.proto b/proto/private/osac/private/v1/public_ips_service.proto index 8337dff6f..421f1a9e3 100644 --- a/proto/private/osac/private/v1/public_ips_service.proto +++ b/proto/private/osac/private/v1/public_ips_service.proto @@ -133,7 +133,7 @@ service PublicIPs { }; } - // Updates an existing public IP. The spec.pool field is immutable; only metadata and compute_instance can change. + // Updates an existing public IP. The spec.pool field is immutable; only metadata can change. rpc Update(PublicIPsUpdateRequest) returns (PublicIPsUpdateResponse) { option (google.api.http) = { patch: "/api/private/v1/public_ips/{object.id}" diff --git a/proto/public/osac/public/v1/public_ips_service.proto b/proto/public/osac/public/v1/public_ips_service.proto index 9e9c3fd3f..db73afd3b 100644 --- a/proto/public/osac/public/v1/public_ips_service.proto +++ b/proto/public/osac/public/v1/public_ips_service.proto @@ -127,7 +127,7 @@ service PublicIPs { }; } - // Updates an existing public IP. Allows modifying spec.compute_instance and metadata (labels, annotations). + // Updates an existing public IP. Allows modifying metadata (labels, annotations). rpc Update(PublicIPsUpdateRequest) returns (PublicIPsUpdateResponse) { option (google.api.http) = { patch: "/api/fulfillment/v1/public_ips/{object.id}" From c3cea4789332bdf6c4b4633bbe67c3eb4405ea99 Mon Sep 17 00:00:00 2001 From: "osac-jira-ai-issue-solver[bot]" <280426608+osac-jira-ai-issue-solver[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:45:17 +0000 Subject: [PATCH 2/4] OSAC-1316: address PR feedback Co-authored-by: osac-dev-bot --- .ai-bot.preserve/config.yaml | 36 +++++++ .ai-bot.preserve/container.json | 3 + .ai-bot.preserve/feedback-workflow.md | 48 +++++++++ .ai-bot.preserve/instructions.md | 128 ++++++++++++++++++++++++ .ai-bot.preserve/new-ticket-workflow.md | 77 ++++++++++++++ 5 files changed, 292 insertions(+) create mode 100644 .ai-bot.preserve/config.yaml create mode 100644 .ai-bot.preserve/container.json create mode 100644 .ai-bot.preserve/feedback-workflow.md create mode 100644 .ai-bot.preserve/instructions.md create mode 100644 .ai-bot.preserve/new-ticket-workflow.md diff --git a/.ai-bot.preserve/config.yaml b/.ai-bot.preserve/config.yaml new file mode 100644 index 000000000..026bb4128 --- /dev/null +++ b/.ai-bot.preserve/config.yaml @@ -0,0 +1,36 @@ +# .ai-bot/config.yaml — fulfillment-service +# +# Per-repository configuration for the jira-ai-issue-solver bot. +# See repoconfig/config.go for the schema. + +# Validation commands the AI can use. These are hints — the AI decides +# when and how to run them. Listed in recommended execution order. +validation_commands: + - "buf lint" + - "buf generate" + - "go generate ./..." + - "gofmt -s -w ." + - "go build ./cmd/fulfillment-service" + - "go build ./cmd/osac" + - "ginkgo run -r internal" + +# Auxiliary repositories cloned into the workspace before AI execution. +imports: + - repo: https://github.com/flightctl/ai-workflows + path: .ai-workflows + ref: main + install: .ai-workflows/install.sh claude + excludes: + - .artifacts/ + +# Pull request settings. +pr: + draft: true + title_prefix: "[AI]" + labels: + - ai-pr + +# AI provider settings. +ai: + claude: + allowed_tools: "Bash Edit Read Write" diff --git a/.ai-bot.preserve/container.json b/.ai-bot.preserve/container.json new file mode 100644 index 000000000..03ae99e37 --- /dev/null +++ b/.ai-bot.preserve/container.json @@ -0,0 +1,3 @@ +{ + "image": "quay.io/rh-ee-andalton/osac-ai:latest" +} diff --git a/.ai-bot.preserve/feedback-workflow.md b/.ai-bot.preserve/feedback-workflow.md new file mode 100644 index 000000000..eba9c443a --- /dev/null +++ b/.ai-bot.preserve/feedback-workflow.md @@ -0,0 +1,48 @@ +# Feedback Workflow + +Read and execute `.ai-workflows/bugfix/skills/feedback.md`. + +All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` +instead. + +Review comments are already provided in the task above (use source 1: task +file). + +## Session Context Recovery + +Before making changes, read `.ai-bot/session-context.md` if it exists. This +file contains the reasoning behind the original implementation (root cause, +design decisions, test strategy). Use it to avoid contradicting prior decisions +unless the reviewer explicitly asks for a different approach. + +## Addressing Comments + +For each review comment: + +1. Read the comment carefully. Understand what is being asked. +2. If the comment requests a code change, implement it. +3. If the comment asks a question, answer it in `.ai-bot/comment-responses.json` + and make any related code changes. +4. If you disagree with a suggestion, explain why in the comment response but + still implement it unless doing so would introduce a correctness bug. + +## Validation After Changes + +After addressing all comments, run the full validation sequence: + +1. `gofmt -s -w .` then `git diff --exit-code` (formatting clean) +2. `buf lint` (if any proto files changed) +3. `ginkgo run -r internal` (unit tests pass) +4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries compile) + +## Comment Responses + +Write a JSON file to `.ai-bot/comment-responses.json` mapping each comment ID +to a short summary of what you did. The bot uses this to post descriptive +replies on the PR instead of generic messages. + +## Iteration Cap + +Maximum 2 fix-test cycles per feedback round. If tests still fail after 2 +attempts, document the failure in the comment response and let the reviewer +decide. diff --git a/.ai-bot.preserve/instructions.md b/.ai-bot.preserve/instructions.md new file mode 100644 index 000000000..f921fa417 --- /dev/null +++ b/.ai-bot.preserve/instructions.md @@ -0,0 +1,128 @@ +# Project Instructions + +This is the fulfillment-service: a gRPC server with REST gateway for managing +infrastructure resources (clusters, hosts, compute instances, networking). It +uses PostgreSQL for storage, OPA for authorization, and supports Kubernetes +deployment via Helm/Kustomize. + +Two binaries: `fulfillment-service` (server) and `osac` (CLI). + +## Validation Commands + +Run these commands to validate your changes. All must pass before committing. + +### Build + +```bash +go build ./cmd/fulfillment-service +go build ./cmd/osac +``` + +### Unit Tests + +```bash +# Run all unit tests (excludes integration tests in it/) +ginkgo run -r internal + +# Run a specific package +ginkgo run internal/servers + +# Run tests matching a pattern +ginkgo run -r internal --focus="CreateCluster" +``` + +Do NOT run `ginkgo run -r` (without restricting to `internal`). That triggers +integration tests which require a kind cluster and take a long time. + +### Code Formatting + +```bash +gofmt -s -w . +# Verify no files changed: +git diff --exit-code +``` + +### Proto Linting and Code Generation + +After editing any `.proto` file, always run both: + +```bash +buf lint +buf generate +``` + +Then verify no generated files changed unexpectedly: + +```bash +git diff --exit-code internal/api/ +``` + +### Module Tidying + +After editing `go.mod`: + +```bash +go mod tidy +``` + +## Coding Standards + +### Architecture + +- Public servers delegate to private servers and add tenant/auth logic. + `ClustersServer` (public) wraps `PrivateClustersServer` (private). +- Server files use builder pattern: `ClustersServerBuilder` configures dependencies. +- Both public and private server files live in `internal/servers/` + (e.g., `clusters_server.go` + `private_clusters_server.go`). +- Database layer uses `GenericDAO[O Object]` for type-safe CRUD on protobuf messages. +- Resources are stored as JSON-serialized protobuf in a `data` column. +- CEL filter expressions are translated to SQL WHERE clauses via `FilterTranslator`. + +### Testing + +- Tests use **Ginkgo v2 + Gomega**. +- Suite setup in `*_suite_test.go` with `BeforeSuite` and `DeferCleanup`. +- `dao.CreateTables[T]()` dynamically creates test schemas. +- Mocks use `go.uber.org/mock` with `//go:generate mockgen` directives. + Mock files live alongside source (e.g., `attribution_logic_mock.go`). + +### Proto Structure + +Protos are split into public and private APIs: + +```text +proto/public/osac/public/v1/ - User-facing API (read-heavy, limited write) +proto/private/osac/private/v1/ - Admin/controller API (full CRUD + Signal RPC) +proto/tests/osac/tests/v1/ - Test-only proto definitions +``` + +Each resource has `_type.proto` (messages) and `s_service.proto` (RPCs). +The `SERVICE_SUFFIX` buf lint rule is intentionally excluded in `buf.yaml`. + +## Files Never to Edit + +These files and directories are generated or managed by external tools. +Never edit them manually: + +- `internal/api/` -- fully generated by `buf generate` from proto files +- `go.sum` -- managed by `go mod tidy` +- `*_mock.go` files -- generated by `mockgen` via `//go:generate` directives +- `charts/` and `it/charts/` template directories -- Helm templates, not test code +- `dist/` -- build artifacts from goreleaser + +## Files to Be Cautious With + +- `proto/**/*.proto` -- changes here cascade to generated code; always run + `buf lint && buf generate` after editing +- `internal/database/migrations/*.up.sql` -- existing migration files must + never be modified; only add new numbered migration files +- `.pre-commit-config.yaml`, `.goreleaser.yaml`, `buf.yaml`, `buf.gen.yaml` -- + infrastructure config; verify with maintainers before changing + +## Pre-commit Hooks + +The repo uses pre-commit with these hooks: +- trailing-whitespace, check-merge-conflict, end-of-file-fixer +- check-added-large-files, check-case-conflict, check-json +- check-symlinks, detect-private-key +- yamllint (strict mode, excludes Helm chart templates) diff --git a/.ai-bot.preserve/new-ticket-workflow.md b/.ai-bot.preserve/new-ticket-workflow.md new file mode 100644 index 000000000..23274d9ba --- /dev/null +++ b/.ai-bot.preserve/new-ticket-workflow.md @@ -0,0 +1,77 @@ +# New Ticket Workflow + +Read and execute `.ai-workflows/bugfix/skills/unattended.md` with these +settings: + +- **branch**: Stay on the current branch (already created by the orchestration + system -- do not create a new branch). +- **lint_command**: `gofmt -s -w .` +- **iteration_cap**: Maximum 3 fix-test cycles before escalating. + +All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` +instead. Write the PR description to `.ai-bot/pr.md`. + +## Repo-Specific Test Commands + +Use these exact commands during the test phase: + +```bash +# Unit tests (mandatory -- always run) +ginkgo run -r internal + +# Focused unit tests (use during iteration to speed up feedback) +ginkgo run -r internal --focus="" +``` + +Do NOT run integration tests (`ginkgo run it`). They require a kind cluster +with specific `/etc/hosts` entries and are validated separately by CI. + +## Repo-Specific Build Commands + +```bash +go build ./cmd/fulfillment-service +go build ./cmd/osac +``` + +## After Proto Changes + +If your fix touches any `.proto` file: + +```bash +buf lint +buf generate +``` + +Then verify the generated code compiles: + +```bash +go build ./cmd/fulfillment-service +``` + +## After Mock Interface Changes + +If your fix modifies an interface that has a `//go:generate mockgen` directive, +regenerate the mock: + +```bash +go generate ./path/to/package/ +``` + +## Final Validation (Before Writing PR Description) + +Run these in order. All must pass: + +1. `gofmt -s -w .` then `git diff --exit-code` (formatting) +2. `buf lint` (proto linting, if protos changed) +3. `ginkgo run -r internal` (full unit test suite) +4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries) + +## Session Context + +After completing the fix, write a session context summary to +`.ai-bot/session-context.md` covering: + +- Root cause summary +- Files changed and why +- Test strategy (what was tested, what was not) +- Risks or areas that need human review From 0b9fbb59eb460493fa434d6c48331857d7f85d6a Mon Sep 17 00:00:00 2001 From: "osac-jira-ai-issue-solver[bot]" <280426608+osac-jira-ai-issue-solver[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:57:14 +0000 Subject: [PATCH 3/4] OSAC-1316: address PR feedback Co-authored-by: osac-dev-bot --- .ai-bot.preserve/config.yaml | 36 ----- .ai-bot.preserve/container.json | 3 - .ai-bot.preserve/feedback-workflow.md | 48 ------- .ai-bot.preserve/instructions.md | 128 ------------------ .ai-bot.preserve/new-ticket-workflow.md | 77 ----------- .gitignore | 1 + .../private/v1/public_ips_service_grpc.pb.go | 4 +- .../public/v1/public_ips_service_grpc.pb.go | 4 +- 8 files changed, 5 insertions(+), 296 deletions(-) delete mode 100644 .ai-bot.preserve/config.yaml delete mode 100644 .ai-bot.preserve/container.json delete mode 100644 .ai-bot.preserve/feedback-workflow.md delete mode 100644 .ai-bot.preserve/instructions.md delete mode 100644 .ai-bot.preserve/new-ticket-workflow.md diff --git a/.ai-bot.preserve/config.yaml b/.ai-bot.preserve/config.yaml deleted file mode 100644 index 026bb4128..000000000 --- a/.ai-bot.preserve/config.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# .ai-bot/config.yaml — fulfillment-service -# -# Per-repository configuration for the jira-ai-issue-solver bot. -# See repoconfig/config.go for the schema. - -# Validation commands the AI can use. These are hints — the AI decides -# when and how to run them. Listed in recommended execution order. -validation_commands: - - "buf lint" - - "buf generate" - - "go generate ./..." - - "gofmt -s -w ." - - "go build ./cmd/fulfillment-service" - - "go build ./cmd/osac" - - "ginkgo run -r internal" - -# Auxiliary repositories cloned into the workspace before AI execution. -imports: - - repo: https://github.com/flightctl/ai-workflows - path: .ai-workflows - ref: main - install: .ai-workflows/install.sh claude - excludes: - - .artifacts/ - -# Pull request settings. -pr: - draft: true - title_prefix: "[AI]" - labels: - - ai-pr - -# AI provider settings. -ai: - claude: - allowed_tools: "Bash Edit Read Write" diff --git a/.ai-bot.preserve/container.json b/.ai-bot.preserve/container.json deleted file mode 100644 index 03ae99e37..000000000 --- a/.ai-bot.preserve/container.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "image": "quay.io/rh-ee-andalton/osac-ai:latest" -} diff --git a/.ai-bot.preserve/feedback-workflow.md b/.ai-bot.preserve/feedback-workflow.md deleted file mode 100644 index eba9c443a..000000000 --- a/.ai-bot.preserve/feedback-workflow.md +++ /dev/null @@ -1,48 +0,0 @@ -# Feedback Workflow - -Read and execute `.ai-workflows/bugfix/skills/feedback.md`. - -All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` -instead. - -Review comments are already provided in the task above (use source 1: task -file). - -## Session Context Recovery - -Before making changes, read `.ai-bot/session-context.md` if it exists. This -file contains the reasoning behind the original implementation (root cause, -design decisions, test strategy). Use it to avoid contradicting prior decisions -unless the reviewer explicitly asks for a different approach. - -## Addressing Comments - -For each review comment: - -1. Read the comment carefully. Understand what is being asked. -2. If the comment requests a code change, implement it. -3. If the comment asks a question, answer it in `.ai-bot/comment-responses.json` - and make any related code changes. -4. If you disagree with a suggestion, explain why in the comment response but - still implement it unless doing so would introduce a correctness bug. - -## Validation After Changes - -After addressing all comments, run the full validation sequence: - -1. `gofmt -s -w .` then `git diff --exit-code` (formatting clean) -2. `buf lint` (if any proto files changed) -3. `ginkgo run -r internal` (unit tests pass) -4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries compile) - -## Comment Responses - -Write a JSON file to `.ai-bot/comment-responses.json` mapping each comment ID -to a short summary of what you did. The bot uses this to post descriptive -replies on the PR instead of generic messages. - -## Iteration Cap - -Maximum 2 fix-test cycles per feedback round. If tests still fail after 2 -attempts, document the failure in the comment response and let the reviewer -decide. diff --git a/.ai-bot.preserve/instructions.md b/.ai-bot.preserve/instructions.md deleted file mode 100644 index f921fa417..000000000 --- a/.ai-bot.preserve/instructions.md +++ /dev/null @@ -1,128 +0,0 @@ -# Project Instructions - -This is the fulfillment-service: a gRPC server with REST gateway for managing -infrastructure resources (clusters, hosts, compute instances, networking). It -uses PostgreSQL for storage, OPA for authorization, and supports Kubernetes -deployment via Helm/Kustomize. - -Two binaries: `fulfillment-service` (server) and `osac` (CLI). - -## Validation Commands - -Run these commands to validate your changes. All must pass before committing. - -### Build - -```bash -go build ./cmd/fulfillment-service -go build ./cmd/osac -``` - -### Unit Tests - -```bash -# Run all unit tests (excludes integration tests in it/) -ginkgo run -r internal - -# Run a specific package -ginkgo run internal/servers - -# Run tests matching a pattern -ginkgo run -r internal --focus="CreateCluster" -``` - -Do NOT run `ginkgo run -r` (without restricting to `internal`). That triggers -integration tests which require a kind cluster and take a long time. - -### Code Formatting - -```bash -gofmt -s -w . -# Verify no files changed: -git diff --exit-code -``` - -### Proto Linting and Code Generation - -After editing any `.proto` file, always run both: - -```bash -buf lint -buf generate -``` - -Then verify no generated files changed unexpectedly: - -```bash -git diff --exit-code internal/api/ -``` - -### Module Tidying - -After editing `go.mod`: - -```bash -go mod tidy -``` - -## Coding Standards - -### Architecture - -- Public servers delegate to private servers and add tenant/auth logic. - `ClustersServer` (public) wraps `PrivateClustersServer` (private). -- Server files use builder pattern: `ClustersServerBuilder` configures dependencies. -- Both public and private server files live in `internal/servers/` - (e.g., `clusters_server.go` + `private_clusters_server.go`). -- Database layer uses `GenericDAO[O Object]` for type-safe CRUD on protobuf messages. -- Resources are stored as JSON-serialized protobuf in a `data` column. -- CEL filter expressions are translated to SQL WHERE clauses via `FilterTranslator`. - -### Testing - -- Tests use **Ginkgo v2 + Gomega**. -- Suite setup in `*_suite_test.go` with `BeforeSuite` and `DeferCleanup`. -- `dao.CreateTables[T]()` dynamically creates test schemas. -- Mocks use `go.uber.org/mock` with `//go:generate mockgen` directives. - Mock files live alongside source (e.g., `attribution_logic_mock.go`). - -### Proto Structure - -Protos are split into public and private APIs: - -```text -proto/public/osac/public/v1/ - User-facing API (read-heavy, limited write) -proto/private/osac/private/v1/ - Admin/controller API (full CRUD + Signal RPC) -proto/tests/osac/tests/v1/ - Test-only proto definitions -``` - -Each resource has `_type.proto` (messages) and `s_service.proto` (RPCs). -The `SERVICE_SUFFIX` buf lint rule is intentionally excluded in `buf.yaml`. - -## Files Never to Edit - -These files and directories are generated or managed by external tools. -Never edit them manually: - -- `internal/api/` -- fully generated by `buf generate` from proto files -- `go.sum` -- managed by `go mod tidy` -- `*_mock.go` files -- generated by `mockgen` via `//go:generate` directives -- `charts/` and `it/charts/` template directories -- Helm templates, not test code -- `dist/` -- build artifacts from goreleaser - -## Files to Be Cautious With - -- `proto/**/*.proto` -- changes here cascade to generated code; always run - `buf lint && buf generate` after editing -- `internal/database/migrations/*.up.sql` -- existing migration files must - never be modified; only add new numbered migration files -- `.pre-commit-config.yaml`, `.goreleaser.yaml`, `buf.yaml`, `buf.gen.yaml` -- - infrastructure config; verify with maintainers before changing - -## Pre-commit Hooks - -The repo uses pre-commit with these hooks: -- trailing-whitespace, check-merge-conflict, end-of-file-fixer -- check-added-large-files, check-case-conflict, check-json -- check-symlinks, detect-private-key -- yamllint (strict mode, excludes Helm chart templates) diff --git a/.ai-bot.preserve/new-ticket-workflow.md b/.ai-bot.preserve/new-ticket-workflow.md deleted file mode 100644 index 23274d9ba..000000000 --- a/.ai-bot.preserve/new-ticket-workflow.md +++ /dev/null @@ -1,77 +0,0 @@ -# New Ticket Workflow - -Read and execute `.ai-workflows/bugfix/skills/unattended.md` with these -settings: - -- **branch**: Stay on the current branch (already created by the orchestration - system -- do not create a new branch). -- **lint_command**: `gofmt -s -w .` -- **iteration_cap**: Maximum 3 fix-test cycles before escalating. - -All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` -instead. Write the PR description to `.ai-bot/pr.md`. - -## Repo-Specific Test Commands - -Use these exact commands during the test phase: - -```bash -# Unit tests (mandatory -- always run) -ginkgo run -r internal - -# Focused unit tests (use during iteration to speed up feedback) -ginkgo run -r internal --focus="" -``` - -Do NOT run integration tests (`ginkgo run it`). They require a kind cluster -with specific `/etc/hosts` entries and are validated separately by CI. - -## Repo-Specific Build Commands - -```bash -go build ./cmd/fulfillment-service -go build ./cmd/osac -``` - -## After Proto Changes - -If your fix touches any `.proto` file: - -```bash -buf lint -buf generate -``` - -Then verify the generated code compiles: - -```bash -go build ./cmd/fulfillment-service -``` - -## After Mock Interface Changes - -If your fix modifies an interface that has a `//go:generate mockgen` directive, -regenerate the mock: - -```bash -go generate ./path/to/package/ -``` - -## Final Validation (Before Writing PR Description) - -Run these in order. All must pass: - -1. `gofmt -s -w .` then `git diff --exit-code` (formatting) -2. `buf lint` (proto linting, if protos changed) -3. `ginkgo run -r internal` (full unit test suite) -4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries) - -## Session Context - -After completing the fix, write a session context summary to -`.ai-bot/session-context.md` covering: - -- Root cause summary -- Files changed and why -- Test strategy (what was tested, what was not) -- Risks or areas that need human review diff --git a/.gitignore b/.gitignore index 391cb4a6c..dea5750f0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /osac-dev __debug_bin* .artifacts +.ai-bot.preserve/ diff --git a/internal/api/osac/private/v1/public_ips_service_grpc.pb.go b/internal/api/osac/private/v1/public_ips_service_grpc.pb.go index 40711db54..2a0570e9b 100644 --- a/internal/api/osac/private/v1/public_ips_service_grpc.pb.go +++ b/internal/api/osac/private/v1/public_ips_service_grpc.pb.go @@ -50,7 +50,7 @@ type PublicIPsClient interface { Get(ctx context.Context, in *PublicIPsGetRequest, opts ...grpc.CallOption) (*PublicIPsGetResponse, error) // Creates a new public IP. The spec.pool field determines which PublicIPPool the address is allocated from. Create(ctx context.Context, in *PublicIPsCreateRequest, opts ...grpc.CallOption) (*PublicIPsCreateResponse, error) - // Updates an existing public IP. The spec.pool field is immutable; only metadata and compute_instance can change. + // Updates an existing public IP. The spec.pool field is immutable; only metadata can change. Update(ctx context.Context, in *PublicIPsUpdateRequest, opts ...grpc.CallOption) (*PublicIPsUpdateResponse, error) // Deletes a public IP. The allocated address is returned to the parent pool's available capacity. Delete(ctx context.Context, in *PublicIPsDeleteRequest, opts ...grpc.CallOption) (*PublicIPsDeleteResponse, error) @@ -136,7 +136,7 @@ type PublicIPsServer interface { Get(context.Context, *PublicIPsGetRequest) (*PublicIPsGetResponse, error) // Creates a new public IP. The spec.pool field determines which PublicIPPool the address is allocated from. Create(context.Context, *PublicIPsCreateRequest) (*PublicIPsCreateResponse, error) - // Updates an existing public IP. The spec.pool field is immutable; only metadata and compute_instance can change. + // Updates an existing public IP. The spec.pool field is immutable; only metadata can change. Update(context.Context, *PublicIPsUpdateRequest) (*PublicIPsUpdateResponse, error) // Deletes a public IP. The allocated address is returned to the parent pool's available capacity. Delete(context.Context, *PublicIPsDeleteRequest) (*PublicIPsDeleteResponse, error) diff --git a/internal/api/osac/public/v1/public_ips_service_grpc.pb.go b/internal/api/osac/public/v1/public_ips_service_grpc.pb.go index 135e48c3f..91ad7c74c 100644 --- a/internal/api/osac/public/v1/public_ips_service_grpc.pb.go +++ b/internal/api/osac/public/v1/public_ips_service_grpc.pb.go @@ -49,7 +49,7 @@ type PublicIPsClient interface { Get(ctx context.Context, in *PublicIPsGetRequest, opts ...grpc.CallOption) (*PublicIPsGetResponse, error) // Creates a new public IP. The spec.pool field determines which PublicIPPool the address is allocated from. Create(ctx context.Context, in *PublicIPsCreateRequest, opts ...grpc.CallOption) (*PublicIPsCreateResponse, error) - // Updates an existing public IP. Allows modifying spec.compute_instance and metadata (labels, annotations). + // Updates an existing public IP. Allows modifying metadata (labels, annotations). Update(ctx context.Context, in *PublicIPsUpdateRequest, opts ...grpc.CallOption) (*PublicIPsUpdateResponse, error) // Deletes a public IP. The allocated address is returned to the parent pool's available capacity. Delete(ctx context.Context, in *PublicIPsDeleteRequest, opts ...grpc.CallOption) (*PublicIPsDeleteResponse, error) @@ -123,7 +123,7 @@ type PublicIPsServer interface { Get(context.Context, *PublicIPsGetRequest) (*PublicIPsGetResponse, error) // Creates a new public IP. The spec.pool field determines which PublicIPPool the address is allocated from. Create(context.Context, *PublicIPsCreateRequest) (*PublicIPsCreateResponse, error) - // Updates an existing public IP. Allows modifying spec.compute_instance and metadata (labels, annotations). + // Updates an existing public IP. Allows modifying metadata (labels, annotations). Update(context.Context, *PublicIPsUpdateRequest) (*PublicIPsUpdateResponse, error) // Deletes a public IP. The allocated address is returned to the parent pool's available capacity. Delete(context.Context, *PublicIPsDeleteRequest) (*PublicIPsDeleteResponse, error) From 48a43fa3ee75c98c0386ee7affd783f66910d630 Mon Sep 17 00:00:00 2001 From: "osac-jira-ai-issue-solver[bot]" <280426608+osac-jira-ai-issue-solver[bot]@users.noreply.github.com> Date: Mon, 15 Jun 2026 12:09:34 +0000 Subject: [PATCH 4/4] OSAC-1316: address PR feedback Co-authored-by: osac-dev-bot --- .ai-bot.preserve/config.yaml | 36 +++++++ .ai-bot.preserve/container.json | 3 + .ai-bot.preserve/feedback-workflow.md | 48 +++++++++ .ai-bot.preserve/instructions.md | 128 ++++++++++++++++++++++++ .ai-bot.preserve/new-ticket-workflow.md | 77 ++++++++++++++ .gitignore | 1 - 6 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 .ai-bot.preserve/config.yaml create mode 100644 .ai-bot.preserve/container.json create mode 100644 .ai-bot.preserve/feedback-workflow.md create mode 100644 .ai-bot.preserve/instructions.md create mode 100644 .ai-bot.preserve/new-ticket-workflow.md diff --git a/.ai-bot.preserve/config.yaml b/.ai-bot.preserve/config.yaml new file mode 100644 index 000000000..026bb4128 --- /dev/null +++ b/.ai-bot.preserve/config.yaml @@ -0,0 +1,36 @@ +# .ai-bot/config.yaml — fulfillment-service +# +# Per-repository configuration for the jira-ai-issue-solver bot. +# See repoconfig/config.go for the schema. + +# Validation commands the AI can use. These are hints — the AI decides +# when and how to run them. Listed in recommended execution order. +validation_commands: + - "buf lint" + - "buf generate" + - "go generate ./..." + - "gofmt -s -w ." + - "go build ./cmd/fulfillment-service" + - "go build ./cmd/osac" + - "ginkgo run -r internal" + +# Auxiliary repositories cloned into the workspace before AI execution. +imports: + - repo: https://github.com/flightctl/ai-workflows + path: .ai-workflows + ref: main + install: .ai-workflows/install.sh claude + excludes: + - .artifacts/ + +# Pull request settings. +pr: + draft: true + title_prefix: "[AI]" + labels: + - ai-pr + +# AI provider settings. +ai: + claude: + allowed_tools: "Bash Edit Read Write" diff --git a/.ai-bot.preserve/container.json b/.ai-bot.preserve/container.json new file mode 100644 index 000000000..03ae99e37 --- /dev/null +++ b/.ai-bot.preserve/container.json @@ -0,0 +1,3 @@ +{ + "image": "quay.io/rh-ee-andalton/osac-ai:latest" +} diff --git a/.ai-bot.preserve/feedback-workflow.md b/.ai-bot.preserve/feedback-workflow.md new file mode 100644 index 000000000..eba9c443a --- /dev/null +++ b/.ai-bot.preserve/feedback-workflow.md @@ -0,0 +1,48 @@ +# Feedback Workflow + +Read and execute `.ai-workflows/bugfix/skills/feedback.md`. + +All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` +instead. + +Review comments are already provided in the task above (use source 1: task +file). + +## Session Context Recovery + +Before making changes, read `.ai-bot/session-context.md` if it exists. This +file contains the reasoning behind the original implementation (root cause, +design decisions, test strategy). Use it to avoid contradicting prior decisions +unless the reviewer explicitly asks for a different approach. + +## Addressing Comments + +For each review comment: + +1. Read the comment carefully. Understand what is being asked. +2. If the comment requests a code change, implement it. +3. If the comment asks a question, answer it in `.ai-bot/comment-responses.json` + and make any related code changes. +4. If you disagree with a suggestion, explain why in the comment response but + still implement it unless doing so would introduce a correctness bug. + +## Validation After Changes + +After addressing all comments, run the full validation sequence: + +1. `gofmt -s -w .` then `git diff --exit-code` (formatting clean) +2. `buf lint` (if any proto files changed) +3. `ginkgo run -r internal` (unit tests pass) +4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries compile) + +## Comment Responses + +Write a JSON file to `.ai-bot/comment-responses.json` mapping each comment ID +to a short summary of what you did. The bot uses this to post descriptive +replies on the PR instead of generic messages. + +## Iteration Cap + +Maximum 2 fix-test cycles per feedback round. If tests still fail after 2 +attempts, document the failure in the comment response and let the reviewer +decide. diff --git a/.ai-bot.preserve/instructions.md b/.ai-bot.preserve/instructions.md new file mode 100644 index 000000000..f921fa417 --- /dev/null +++ b/.ai-bot.preserve/instructions.md @@ -0,0 +1,128 @@ +# Project Instructions + +This is the fulfillment-service: a gRPC server with REST gateway for managing +infrastructure resources (clusters, hosts, compute instances, networking). It +uses PostgreSQL for storage, OPA for authorization, and supports Kubernetes +deployment via Helm/Kustomize. + +Two binaries: `fulfillment-service` (server) and `osac` (CLI). + +## Validation Commands + +Run these commands to validate your changes. All must pass before committing. + +### Build + +```bash +go build ./cmd/fulfillment-service +go build ./cmd/osac +``` + +### Unit Tests + +```bash +# Run all unit tests (excludes integration tests in it/) +ginkgo run -r internal + +# Run a specific package +ginkgo run internal/servers + +# Run tests matching a pattern +ginkgo run -r internal --focus="CreateCluster" +``` + +Do NOT run `ginkgo run -r` (without restricting to `internal`). That triggers +integration tests which require a kind cluster and take a long time. + +### Code Formatting + +```bash +gofmt -s -w . +# Verify no files changed: +git diff --exit-code +``` + +### Proto Linting and Code Generation + +After editing any `.proto` file, always run both: + +```bash +buf lint +buf generate +``` + +Then verify no generated files changed unexpectedly: + +```bash +git diff --exit-code internal/api/ +``` + +### Module Tidying + +After editing `go.mod`: + +```bash +go mod tidy +``` + +## Coding Standards + +### Architecture + +- Public servers delegate to private servers and add tenant/auth logic. + `ClustersServer` (public) wraps `PrivateClustersServer` (private). +- Server files use builder pattern: `ClustersServerBuilder` configures dependencies. +- Both public and private server files live in `internal/servers/` + (e.g., `clusters_server.go` + `private_clusters_server.go`). +- Database layer uses `GenericDAO[O Object]` for type-safe CRUD on protobuf messages. +- Resources are stored as JSON-serialized protobuf in a `data` column. +- CEL filter expressions are translated to SQL WHERE clauses via `FilterTranslator`. + +### Testing + +- Tests use **Ginkgo v2 + Gomega**. +- Suite setup in `*_suite_test.go` with `BeforeSuite` and `DeferCleanup`. +- `dao.CreateTables[T]()` dynamically creates test schemas. +- Mocks use `go.uber.org/mock` with `//go:generate mockgen` directives. + Mock files live alongside source (e.g., `attribution_logic_mock.go`). + +### Proto Structure + +Protos are split into public and private APIs: + +```text +proto/public/osac/public/v1/ - User-facing API (read-heavy, limited write) +proto/private/osac/private/v1/ - Admin/controller API (full CRUD + Signal RPC) +proto/tests/osac/tests/v1/ - Test-only proto definitions +``` + +Each resource has `_type.proto` (messages) and `s_service.proto` (RPCs). +The `SERVICE_SUFFIX` buf lint rule is intentionally excluded in `buf.yaml`. + +## Files Never to Edit + +These files and directories are generated or managed by external tools. +Never edit them manually: + +- `internal/api/` -- fully generated by `buf generate` from proto files +- `go.sum` -- managed by `go mod tidy` +- `*_mock.go` files -- generated by `mockgen` via `//go:generate` directives +- `charts/` and `it/charts/` template directories -- Helm templates, not test code +- `dist/` -- build artifacts from goreleaser + +## Files to Be Cautious With + +- `proto/**/*.proto` -- changes here cascade to generated code; always run + `buf lint && buf generate` after editing +- `internal/database/migrations/*.up.sql` -- existing migration files must + never be modified; only add new numbered migration files +- `.pre-commit-config.yaml`, `.goreleaser.yaml`, `buf.yaml`, `buf.gen.yaml` -- + infrastructure config; verify with maintainers before changing + +## Pre-commit Hooks + +The repo uses pre-commit with these hooks: +- trailing-whitespace, check-merge-conflict, end-of-file-fixer +- check-added-large-files, check-case-conflict, check-json +- check-symlinks, detect-private-key +- yamllint (strict mode, excludes Helm chart templates) diff --git a/.ai-bot.preserve/new-ticket-workflow.md b/.ai-bot.preserve/new-ticket-workflow.md new file mode 100644 index 000000000..23274d9ba --- /dev/null +++ b/.ai-bot.preserve/new-ticket-workflow.md @@ -0,0 +1,77 @@ +# New Ticket Workflow + +Read and execute `.ai-workflows/bugfix/skills/unattended.md` with these +settings: + +- **branch**: Stay on the current branch (already created by the orchestration + system -- do not create a new branch). +- **lint_command**: `gofmt -s -w .` +- **iteration_cap**: Maximum 3 fix-test cycles before escalating. + +All artifact paths (`.artifacts/bugfix/{issue}/`) should use `.ai-bot/` +instead. Write the PR description to `.ai-bot/pr.md`. + +## Repo-Specific Test Commands + +Use these exact commands during the test phase: + +```bash +# Unit tests (mandatory -- always run) +ginkgo run -r internal + +# Focused unit tests (use during iteration to speed up feedback) +ginkgo run -r internal --focus="" +``` + +Do NOT run integration tests (`ginkgo run it`). They require a kind cluster +with specific `/etc/hosts` entries and are validated separately by CI. + +## Repo-Specific Build Commands + +```bash +go build ./cmd/fulfillment-service +go build ./cmd/osac +``` + +## After Proto Changes + +If your fix touches any `.proto` file: + +```bash +buf lint +buf generate +``` + +Then verify the generated code compiles: + +```bash +go build ./cmd/fulfillment-service +``` + +## After Mock Interface Changes + +If your fix modifies an interface that has a `//go:generate mockgen` directive, +regenerate the mock: + +```bash +go generate ./path/to/package/ +``` + +## Final Validation (Before Writing PR Description) + +Run these in order. All must pass: + +1. `gofmt -s -w .` then `git diff --exit-code` (formatting) +2. `buf lint` (proto linting, if protos changed) +3. `ginkgo run -r internal` (full unit test suite) +4. `go build ./cmd/fulfillment-service && go build ./cmd/osac` (both binaries) + +## Session Context + +After completing the fix, write a session context summary to +`.ai-bot/session-context.md` covering: + +- Root cause summary +- Files changed and why +- Test strategy (what was tested, what was not) +- Risks or areas that need human review diff --git a/.gitignore b/.gitignore index dea5750f0..391cb4a6c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,3 @@ /osac-dev __debug_bin* .artifacts -.ai-bot.preserve/