From 41b44bbc6c34c6105035ba341c6a85745fd0f439 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Sat, 17 Oct 2026 18:24:10 +0200 Subject: [PATCH] docs: drop monorepo residue from workflow docs and code comments The workflows README described the monorepo's Lambda, Fargate, Cloud Run and Azure deploy pipelines. Rewrite it for this repository's four workflows (ci, pre-commit, mcp-server-json, release), with each claim taken from the YAML. CONTRIBUTING asked bug reporters for `./cudly --version`. This binary has no version flag, so ask for the release tag or commit instead. Comments in server.go, cmd/cudly-mcp/main.go, tools/ and docs/mcp-annotations-decisions.md cited mcp/... paths, the CLI's cmd/main.go and monorepo planning notes. Point them at root-relative paths, or drop citations to files that do not exist here. Comments only, no behaviour change. Refs #2 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/README.md | 703 ++---------------------------- CONTRIBUTING.md | 2 +- cmd/cudly-mcp/main.go | 6 +- docs/mcp-annotations-decisions.md | 11 +- server.go | 2 +- server_test.go | 4 +- tools/aws_savingsplans.go | 2 +- tools/azure_compute_ri.go | 2 +- tools/azure_compute_ri_test.go | 2 +- tools/enums.go | 5 +- tools/list_commitment_actions.go | 4 +- tools/registry.go | 9 +- 12 files changed, 56 insertions(+), 696 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 6520a48..5f7b491 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,686 +1,51 @@ # GitHub Actions Workflows -This directory contains CI/CD workflows for the CUDly project, providing automated testing, deployment, and operations across AWS, GCP, and Azure. +CI and release workflows for the cloud-commitments-mcp server. CI needs no cloud +credentials; `snyk-scan` reads the `SNYK_TOKEN` secret. -## 📋 Workflows Overview +| Workflow | Trigger | Purpose | +|----------|---------|---------| +| `ci.yml` | PR and push to `main`/`develop`, manual | Lint, test, build and scan | +| `pre-commit.yml` | PR and push to `main` | Runs the repo's pre-commit hooks | +| `mcp-server-json.yml` | PRs touching `server.json` or its validator, `v*` tags, manual | Validates `server.json` | +| `release.yml` | `v*` tag push | Builds and publishes a release | -| Workflow | Purpose | Trigger | Duration | -|----------|---------|---------|----------| -| [ci.yml](#ci-workflow) | Continuous Integration | PR, Push to main | ~10 min | -| [deploy-aws-lambda.yml](#aws-lambda-deployment) | Deploy to AWS Lambda | Push to main, Manual | ~8 min | -| [deploy-aws-fargate.yml](#aws-fargate-deployment) | Deploy to AWS Fargate | Manual | ~10 min | -| [deploy-gcp.yml](#gcp-deployment) | Deploy to GCP Cloud Run | Manual | ~8 min | -| [deploy-azure.yml](#azure-deployment) | Deploy to Azure Container Apps | Manual | ~10 min | -| [deploy-all.yml](#multi-cloud-deployment) | Deploy to all clouds | Manual, Release | ~15 min | -| [database-migration.yml](#database-migrations) | Run DB migrations | Manual | ~5 min | -| [rollback.yml](#rollback) | Rollback deployment | Manual | ~5 min | +## ci.yml -> **Note:** Frontend deployment is handled automatically via Terraform as part of the backend deployment workflows. +Jobs: `lint` (golangci-lint, `go vet`, cyclomatic complexity), `workflow-lint` (actionlint, +zizmor), `unit-tests` (coverage check, warns under 80%), `mcp-build` (builds +`bin/cudly-mcp` on an OS matrix), `integration-tests`, `security-scan` (govulncheck, gosec, +Trivy) and `snyk-scan`. ---- +The `ci-success` job aggregates `lint`, `workflow-lint`, `unit-tests`, `integration-tests`, +`security-scan` and `mcp-build`. It fails unless each of them reports exactly `success`, so a +skipped job cannot pass the gate. `snyk-scan` is not in that list. It skips fork PRs, and its +step is `continue-on-error`. Use `ci-success` as the required status check. -## CI Workflow +## pre-commit.yml -**File:** `ci.yml` +Installs the hook tooling (gocyclo, Trivy, git-secrets, pre-commit), self-tests the +git-secrets allowlist, then runs `pre-commit` against `.pre-commit-config.yaml`. -### Purpose +## mcp-server-json.yml -Runs comprehensive quality checks on every pull request and push to main branch. +`validate-schema` checks `server.json` against the MCP Registry schema. On `v*` tags, +`assert-version-matches-tag` also requires the `server.json` version to equal the tag. -### Jobs +## release.yml -1. **Lint** - golangci-lint, go vet -2. **Unit Tests** - Go tests with race detection, coverage reporting -3. **Integration Tests** - Tests with real PostgreSQL -4. **Docker Build** - Build and test Docker image -5. **Terraform Validate** - Validate all Terraform configs (AWS, GCP, Azure) -6. **Security Scan** - gosec, trivy, tfsec -7. **Snyk Scan** - Dependency vulnerability scanning -8. **E2E Tests** - Docker Compose end-to-end tests -9. **Cost Estimate** - Infracost cost estimation (PR only) +Pushing a `v*` tag runs, in order: `consistency-gate` (`server.json` and +`mcpb/manifest.json` versions match the tag), `test`, `goreleaser` (binaries and GitHub +Release), `mcpb` (bundle asset) and `publish-registry` (MCP Registry via GitHub OIDC). +Only one run per ref at a time. The publishing jobs use the `release` environment. -### Triggers - -- Pull requests to `main` or `develop` -- Pushes to `main` or `develop` -- Manual dispatch - -### Required Secrets - -- `SNYK_TOKEN` (optional - for Snyk scanning) -- `INFRACOST_API_KEY` (optional - for cost estimation) - -### Required Variables - -- `GO_VERSION` (default: 1.26.9) - -### Example - -```bash -# Automatically runs on PR -git push origin feature-branch - -# Or trigger manually -gh workflow run ci.yml -``` - ---- - -## AWS Lambda Deployment - -**File:** `deploy-aws-lambda.yml` - -### Purpose - -Deploy CUDly to AWS Lambda with Function URL. Serverless, event-driven platform. - -### Jobs - -1. **Prepare** - Determine environment and image tag -2. **Build & Push** - Build Docker image, push to ECR -3. **Deploy** - Deploy with Terraform -4. **Test** - Health check and smoke tests - -### Triggers - -- Push to `main` (deploys to dev) -- Release creation (deploys to prod) -- Manual dispatch with environment selection - -### Required Secrets - -- `AWS_ACCESS_KEY_ID` -- `AWS_SECRET_ACCESS_KEY` - -### Required Variables - -- `AWS_REGION` (default: us-east-1) -- `AWS_ACCOUNT_ID` -- `ECR_REPOSITORY` (default: cudly) - -### Example - -```bash -# Deploy to dev -gh workflow run deploy-aws-lambda.yml -f environment=dev - -# Push to main also deploys to dev -git push origin main - -# Deploy to prod -gh release create v1.0.0 -``` - -### Output - -- Function URL: `https://.lambda-url.us-east-1.on.aws` -- Deployment info artifact - ---- - -## AWS Fargate Deployment - -**File:** `deploy-aws-fargate.yml` - -### Purpose - -Deploy CUDly to AWS ECS Fargate with ALB. Always-on containerized platform. - -### Jobs - -1. **Build & Push** - Build Docker image, push to ECR -2. **Deploy** - Deploy with Terraform (Fargate mode) -3. **Test** - Health check verification - -### Triggers - -- Manual dispatch only - -### Required Secrets - -- Same as AWS Lambda - -### Example - -```bash -# Deploy to staging with Fargate -gh workflow run deploy-aws-fargate.yml -f environment=staging -``` - ---- - -## GCP Deployment - -**File:** `deploy-gcp.yml` - -### Purpose - -Deploy CUDly to GCP Cloud Run. Serverless container platform. - -### Jobs - -1. **Build & Deploy** - Build, push to Artifact Registry, deploy with Terraform -2. **Test** - Health check and smoke tests - -### Triggers - -- Manual dispatch -- Called by deploy-all.yml - -### Required Secrets - -- `GCP_SA_KEY` (Service Account JSON with permissions) -- `GCP_PROJECT_ID` - -### Required Variables - -- `GCP_REGION` (default: us-central1) -- `ARTIFACT_REGISTRY_REPO` (default: cudly) - -### Example - -```bash -# Deploy to GCP dev -gh workflow run deploy-gcp.yml -f environment=dev -``` - -### Output - -- Service URL: `https://cudly--uc.a.run.app` - ---- - -## Azure Deployment - -**File:** `deploy-azure.yml` - -### Purpose - -Deploy CUDly to Azure Container Apps. Serverless container platform with built-in HTTPS. - -### Jobs - -1. **Build & Deploy** - Build, push to ACR, deploy with Terraform -2. **Test** - Health check and smoke tests - -### Triggers - -- Manual dispatch -- Called by deploy-all.yml - -### Required Secrets - -- `AZURE_CREDENTIALS` (Service Principal JSON) -- `AZURE_SUBSCRIPTION_ID` - -### Required Variables - -- `AZURE_LOCATION` (default: eastus) -- `ACR_NAME` (default: cudlyacr) -- `RESOURCE_GROUP` (default: cudly-rg) - -### Example - -```bash -# Deploy to Azure staging -gh workflow run deploy-azure.yml -f environment=staging -``` - -### Output - -- App URL: `https://..azurecontainerapps.io` - ---- - -## Multi-Cloud Deployment - -**File:** `deploy-all.yml` - -### Purpose - -Orchestrate deployment to multiple cloud providers in parallel. - -### Jobs - -1. **Determine Strategy** - Choose which clouds to deploy to -2. **Deploy AWS Lambda** - Parallel deployment -3. **Deploy AWS Fargate** - Parallel deployment (optional) -4. **Deploy GCP** - Parallel deployment -5. **Deploy Azure** - Parallel deployment -6. **Notify** - Aggregate results - -### Triggers - -- Manual dispatch with provider selection -- Release creation (deploys to all clouds in prod) - -### Required Secrets - -- All secrets from individual deployment workflows - -### Deployment Options - -- `all` - Deploy to AWS, GCP, and Azure -- `aws-only` - AWS Lambda only -- `gcp-only` - GCP Cloud Run only -- `azure-only` - Azure Container Apps only -- `aws-gcp` - AWS and GCP -- `aws-azure` - AWS and Azure -- `gcp-azure` - GCP and Azure - -### Example - -```bash -# Deploy to all clouds (staging) -gh workflow run deploy-all.yml -f environment=staging -f deploy_to=all - -# Deploy to AWS and GCP (prod) -gh workflow run deploy-all.yml -f environment=prod -f deploy_to=aws-gcp - -# Automatic on release -gh release create v1.0.0 -``` - -### Benefits - -- **Disaster Recovery** - Multi-cloud redundancy -- **Cost Optimization** - Compare costs across providers -- **Testing** - Validate across all platforms -- **Global Reach** - Deploy to optimal regions per cloud - ---- - -## Database Migrations - -**File:** `database-migration.yml` - -### Purpose - -Apply or rollback database schema migrations across cloud providers. - -### Jobs - -1. **Validate** - Safety checks -2. **Migrate AWS** - Run golang-migrate on Aurora -3. **Migrate GCP** - Run golang-migrate on Cloud SQL -4. **Migrate Azure** - Run golang-migrate on Flexible Server - -### Triggers - -- Manual dispatch only (safety measure) -- Can be called by deployment workflows - -### Required Secrets - -- `DB_PASSWORD_AWS` -- `DB_PASSWORD_GCP` -- `DB_PASSWORD_AZURE` -- Cloud credentials (same as deployment workflows) - -### Required Variables - -- Database endpoints per environment - -### Migration Directions - -- `up` - Apply migrations (default) -- `down` - Rollback migrations (DANGEROUS) - -### Example - -```bash -# Apply all migrations to AWS dev -gh workflow run database-migration.yml \ - -f cloud=aws \ - -f environment=dev \ - -f direction=up - -# Rollback last 2 migrations on GCP staging -gh workflow run database-migration.yml \ - -f cloud=gcp \ - -f environment=staging \ - -f direction=down \ - -f steps=2 - -# Rollback 1 migration on AWS prod (requires typed confirmation) -gh workflow run database-migration.yml \ - -f cloud=aws \ - -f environment=prod \ - -f direction=down \ - -f steps=1 \ - -f confirm=rollback-prod - -# Apply to all clouds -gh workflow run database-migration.yml \ - -f cloud=all \ - -f environment=prod \ - -f direction=up -``` - -### Safety Features - -- **Validation** - Checks migration files exist before running -- **Explicit steps required** - `direction=down` requires an explicit positive `steps` value; `steps=0` (the default, which would run `down -all` and drop the entire schema) is rejected -- **Production confirmation** - `direction=down` on `environment=prod` additionally requires typing `rollback-prod` in the `confirm` input; omitting or mistyping it blocks the run -- **Defense in depth** - each migrate job independently re-validates the positive-steps constraint, so a future validate regression cannot reach `down -all` -- **Audit Trail** - Records all migrations in the step summary - ---- - -## Rollback - -**File:** `rollback.yml` - -### Purpose - -Quickly rollback to a previous deployment version by redeploying a known-good Docker image. - -### Jobs - -1. **Validate** - Validate image tag and construct image URI -2. **Rollback** - Confirm the image exists in the registry, then deploy it with Terraform -3. **Summary** - Create audit record - -Image existence is verified *inside* each rollback job rather than in a -standalone job. A separate verify job would have to assume the same cloud -deploy role while carrying no `environment:` binding, which is exactly the -ungated-but-credentialed shape that made the workflow exploitable. The -tradeoff is that a rollback to a nonexistent tag now fails after the -environment approval rather than before it. - -### Triggers - -- Manual dispatch only (safety measure) - -### Required Secrets - -- Cloud credentials (same as deployment workflows) - -### Example - -```bash -# Rollback AWS Lambda production to previous version -gh workflow run rollback.yml \ - -f cloud=aws-lambda \ - -f environment=prod \ - -f image_tag=sha-abc123 \ - -f reason="Critical bug in v1.2.3" - -# Rollback GCP staging -gh workflow run rollback.yml \ - -f cloud=gcp \ - -f environment=staging \ - -f image_tag=v1.2.2 -``` - -### Safety Features - -- **Image Verification** - Confirms image exists before deploying -- **Audit Trail** - Records all rollbacks (365 day retention) -- **Reason Tracking** - Requires reason for accountability -- **Manual Only** - Cannot be triggered automatically - -### Finding Image Tags - -```bash -# AWS ECR -aws ecr list-images --repository-name cudly - -# GCP Artifact Registry -gcloud artifacts docker images list -docker.pkg.dev///cudly - -# Azure ACR -az acr repository show-tags --name cudlyacr --repository cudly -``` - ---- - -## Setup Guide - -### 1. Configure GitHub Secrets - -**AWS:** - -```bash -# Create secrets -gh secret set AWS_ACCESS_KEY_ID -gh secret set AWS_SECRET_ACCESS_KEY -gh secret set DB_PASSWORD_AWS -``` - -**GCP:** - -```bash -# Create service account and download JSON -gcloud iam service-accounts create cudly-cicd --project= - -# Grant permissions -gcloud projects add-iam-policy-binding \ - --member="serviceAccount:cudly-cicd@.iam.gserviceaccount.com" \ - --role="roles/run.admin" - -# Create and download key -gcloud iam service-accounts keys create key.json \ - --iam-account=cudly-cicd@.iam.gserviceaccount.com - -# Set secrets -gh secret set GCP_SA_KEY < key.json -gh secret set GCP_PROJECT_ID -b"" -gh secret set DB_PASSWORD_GCP -``` - -**Azure:** - -```bash -# Create service principal -az ad sp create-for-rbac --name cudly-cicd --sdk-auth > azure-credentials.json - -# Set secrets -gh secret set AZURE_CREDENTIALS < azure-credentials.json -gh secret set AZURE_SUBSCRIPTION_ID -b"" -gh secret set DB_PASSWORD_AZURE -``` - -**Optional:** - -```bash -gh secret set SNYK_TOKEN -gh secret set INFRACOST_API_KEY -``` - -### 2. Configure GitHub Variables - -```bash -# AWS -gh variable set AWS_REGION -b"us-east-1" -gh variable set AWS_ACCOUNT_ID -b"123456789012" -gh variable set ECR_REPOSITORY -b"cudly" - -# GCP -gh variable set GCP_REGION -b"us-central1" -gh variable set ARTIFACT_REGISTRY_REPO -b"cudly" - -# Azure -gh variable set AZURE_LOCATION -b"eastus" -gh variable set ACR_NAME -b"cudlyacr" -gh variable set RESOURCE_GROUP -b"cudly-rg" - -# Frontend -gh variable set CLOUD_PROVIDER -b"aws" -gh variable set FRONTEND_BUCKET -b"cudly-frontend-prod" -gh variable set CLOUDFRONT_DISTRIBUTION_ID -b"E1234567890" -gh variable set API_URL -b"https://api.cudly.example.com" -``` - -### 3. Set Up Environments - -GitHub Environments provide deployment protection and environment-specific secrets: - -1. Go to **Settings** → **Environments** -2. Create environments: - - `aws-lambda-dev`, `aws-lambda-staging`, `aws-lambda-prod` - - `aws-fargate-dev`, `aws-fargate-staging`, `aws-fargate-prod` - - `gcp-dev`, `gcp-staging`, `gcp-prod` - - `azure-dev`, `azure-staging`, `azure-prod` - - `frontend-aws-dev`, etc. - -3. Configure protection rules: - - **Production**: Require approvals, restrict to main branch - - **Staging**: Optional approvals - - **Dev**: No restrictions - ---- - -## Troubleshooting - -### CI Workflow Fails - -**Unit tests fail:** +## Running the checks locally ```bash -# Run locally +make build # bin/cudly-mcp make test-unit +make vet +make lint +make ci # fmt, vet, complexity, test-unit, security-scan +pip install pre-commit && pre-commit install # then: pre-commit run --all-files ``` - -**Integration tests fail:** - -```bash -# Run with testcontainers -make test-integration -``` - -**Security scan fails:** - -```bash -# Run locally -make security-scan-all -``` - -### Deployment Fails - -**AWS - Image not found:** - -```bash -# Check ECR -aws ecr describe-images --repository-name cudly --region us-east-1 - -# Re-push image -docker push .dkr.ecr.us-east-1.amazonaws.com/cudly:latest -``` - -**GCP - Permission denied:** - -```bash -# Check service account permissions -gcloud projects get-iam-policy - -# Grant missing roles -gcloud projects add-iam-policy-binding \ - --member="serviceAccount:@.iam.gserviceaccount.com" \ - --role="roles/run.admin" -``` - -**Azure - Resource not found:** - -```bash -# Verify resource group exists -az group show --name cudly-rg - -# Create if missing -az group create --name cudly-rg --location eastus -``` - -### Database Migration Fails - -**Connection timeout:** - -- Check database security groups/firewall rules -- Verify VPN/bastion access if required -- Check database is running - -**Migration already applied:** - -```bash -# Check current version -migrate -path migrations -database version - -# Force version (use with caution) -migrate -path migrations -database force -``` - ---- - -## Best Practices - -### 1. Branch Protection - -- Require CI to pass before merging -- Require code reviews -- Restrict direct pushes to main - -### 2. Environment Strategy - -- **Dev**: Auto-deploy on push to develop branch -- **Staging**: Auto-deploy on push to main -- **Prod**: Manual approval required, deploy on release - -### 3. Rollback Strategy - -- Keep last 10 images in each registry -- Document rollback procedures -- Test rollback in staging first - -### 4. Monitoring - -- Set up CloudWatch/Cloud Logging alerts -- Monitor deployment success rates -- Track deployment frequency - -### 5. Security - -- Rotate secrets regularly -- Use environment protection rules -- Enable secret scanning -- Review security scan results - ---- - -## Metrics & Monitoring - -### Workflow Success Rate - -```bash -# View recent workflow runs -gh run list --limit 50 - -# View specific workflow -gh run list --workflow=ci.yml --limit 20 -``` - -### Deployment Frequency - -- Target: Multiple deployments per day -- Track via GitHub Actions insights - -### Mean Time to Recovery (MTTR) - -- Use rollback workflow for quick recovery -- Target: < 15 minutes - -### CI Duration - -- Unit tests: ~5 min -- Integration tests: ~3 min -- Security scans: ~2 min -- Total: ~10 min target - ---- - -## Additional Resources - -- [GitHub Actions Documentation](https://docs.github.com/en/actions) -- [AWS ECR Documentation](https://docs.aws.amazon.com/ecr/) -- [GCP Artifact Registry](https://cloud.google.com/artifact-registry/docs) -- [Azure Container Registry](https://docs.microsoft.com/en-us/azure/container-registry/) -- [golang-migrate](https://github.com/golang-migrate/migrate) -- [Terraform Cloud](https://www.terraform.io/cloud) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d0975e..16fa7ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ By participating in this project, you agree to maintain a respectful and inclusi 1. **Search existing issues** - Check if the bug has already been reported 2. **Create a detailed report** including: - - CUDly version (`./cudly --version`) + - CUDly MCP server version (`bin/cudly-mcp` has no version flag: give the release tag, or `git rev-parse --short HEAD` for a source build) - Go version (`go version`) - Operating system and architecture - Cloud provider and service affected diff --git a/cmd/cudly-mcp/main.go b/cmd/cudly-mcp/main.go index 18d831a..5e2d527 100644 --- a/cmd/cudly-mcp/main.go +++ b/cmd/cudly-mcp/main.go @@ -1,10 +1,8 @@ // Command cudly-mcp runs the CUDly MCP server on stdio, exposing CUDly's // RI/SP/CUD search and purchase tools to any MCP client (e.g. Claude Code -// via ~/.claude/mcp.json). See mcp/README.md for setup and usage. +// via ~/.claude/mcp.json). See README.md for setup and usage. // -// This binary is intentionally separate from the ri-helper CLI (cmd/main.go): -// it is a local/desktop MCP server, never a Lambda handler, and is kept out -// of iac/ and terraform/ (see mcp/README.md "Deployment model"). +// This binary is a local/desktop MCP server, never a Lambda handler. package main import ( diff --git a/docs/mcp-annotations-decisions.md b/docs/mcp-annotations-decisions.md index 2fe6b83..6f85124 100644 --- a/docs/mcp-annotations-decisions.md +++ b/docs/mcp-annotations-decisions.md @@ -3,9 +3,8 @@ This repo has no existing ADR/`docs/decisions/` convention (checked at implementation time: no `docs/adr/` or `docs/decisions/` directory), so this rationale lives here instead of in a numbered ADR. -Context: `docs/plans/mcp/05-store.md` Phase A and `docs/plans/mcp/00-scope.md` -§6 (not checked into this repo -- local planning notes for the MCP -store-readiness workstream). +Context: the MCP store-readiness workstream (planning notes are not +checked into this repo). ## Why annotations at all @@ -26,7 +25,7 @@ specifically: `ReadOnlyHint bool` and `IdempotentHint bool` have no such trap (their zero value, `false`, is already the conservative reading), but every Descriptor still sets them explicitly via `readOnlyAnnotations`/`purchaseAnnotations` -(`mcp/tools/registry.go`) so the intent is legible at every call site rather +(`tools/registry.go`) so the intent is legible at every call site rather than resting on an implicit zero value. ## D1 -- destructiveHint=true on every purchase tool @@ -51,7 +50,7 @@ therefore set `DestructiveHint: boolPtr(true)`. ## A5 -- idempotentHint=false on every purchase tool, always Every purchase tool's `IdempotentHint` is `false`, unconditionally, even -though `ExecutePurchase` (`mcp/tools/purchase.go`) already derives an +though `ExecutePurchase` (`tools/purchase.go`) already derives an idempotency key from the request and refuses/dedupes a byte-identical retry. Rejected alternative: `IdempotentHint=true`, on the theory that the @@ -77,7 +76,7 @@ Rejected because: ## Per-tool annotation table -Built from `mcp/tools/registry.go`'s `readOnlyAnnotations`/ +Built from `tools/registry.go`'s `readOnlyAnnotations`/ `purchaseAnnotations` helpers and each tool's `Descriptor()`. Every tool sets `ReadOnlyHint`, `DestructiveHint`, `IdempotentHint`, and `OpenWorldHint` explicitly; none rely on the SDK's nil-defaults-to-true behavior. diff --git a/server.go b/server.go index 4cc5190..6d02e04 100644 --- a/server.go +++ b/server.go @@ -1,5 +1,5 @@ // Package mcp wires the CUDly MCP server: it registers every tool from -// mcp/tools onto a github.com/modelcontextprotocol/go-sdk/mcp.Server and +// tools/ onto a github.com/modelcontextprotocol/go-sdk/mcp.Server and // builds the cudly_list_commitment_actions catalog from those same tools' // descriptors, so the live tool set and the discoverability catalog can // never drift apart. diff --git a/server_test.go b/server_test.go index 55eb5e6..95b9f18 100644 --- a/server_test.go +++ b/server_test.go @@ -136,7 +136,7 @@ func TestRegistryNonEmpty(t *testing.T) { // without any AWS credentials configured in this test environment -- // confirming dry_run=true never reaches the real purchase path even through // the full protocol stack, not just the Go-level unit tests in -// mcp/tools/aws_ec2_ri_test.go. +// tools/aws_ec2_ri_test.go. func TestEndToEndSearchThenDryRunPurchase(t *testing.T) { t.Parallel() ctx := context.Background() @@ -252,7 +252,7 @@ func TestRealPurchaseToolsDocumentMoneyImpactAndDryRun(t *testing.T) { // TestAzureComputeRIPurchaseSchemaExcludesPartialUpfront proves the // cudly_azure_compute_ri_purchase tool's advertised payment_option enum // never offers partial-upfront: Azure has no partial-upfront billing plan -// (mcp/tools/azure_compute_ri.go rejects it at runtime as defense in depth), +// (tools/azure_compute_ri.go rejects it at runtime as defense in depth), // so the schema itself must not invite a caller to pick a value the tool // can only ever refuse. Drives the real MCP protocol (ListTools), not a // bare Go function call, so it catches a regression in what a real client diff --git a/tools/aws_savingsplans.go b/tools/aws_savingsplans.go index 994ee48..e3dc0bf 100644 --- a/tools/aws_savingsplans.go +++ b/tools/aws_savingsplans.go @@ -189,7 +189,7 @@ func savingsPlanRecommendationFromArgs(args savingsPlansPurchaseArgs) (rec commo // Account-level plan types (Compute/SageMaker/Database) ignore region // entirely, so pin the canonical one rather than honoring whatever the // caller passed. region flows into rec.Region and from there into - // idempotencyKeyFor (mcp/tools/purchase.go), so letting an IGNORED input + // idempotencyKeyFor (tools/purchase.go), so letting an IGNORED input // through would fork purchase identity: buying a $10/hr Compute SP once // without region and then re-issuing the identical call with // region="eu-west-1" (a self-correction, or a retry that fills the field diff --git a/tools/azure_compute_ri.go b/tools/azure_compute_ri.go index ccae651..2b85e21 100644 --- a/tools/azure_compute_ri.go +++ b/tools/azure_compute_ri.go @@ -173,7 +173,7 @@ func azureComputeRecommendationFromArgs(args azureComputeRIPurchaseArgs) (rec co } // payment_option defaults to no-upfront (matching the CLI's --payment - // default, cmd/main.go) when the caller omits it -- an omitted string + // default in the cloud-commitments-cli repo) when the caller omits it -- an omitted string // field arrives as "" and is never confused with an explicit, // unrecognized value (feedback_no_silent_fallbacks: the default is // applied here, explicitly, not fabricated deeper in the stack). diff --git a/tools/azure_compute_ri_test.go b/tools/azure_compute_ri_test.go index 6bcef30..7f97c00 100644 --- a/tools/azure_compute_ri_test.go +++ b/tools/azure_compute_ri_test.go @@ -146,7 +146,7 @@ func TestAzureComputeRecommendationFromArgsAcceptsNoUpfront(t *testing.T) { // TestAzureComputeRecommendationFromArgsDefaultsToNoUpfront proves omitting // payment_option defaults to no-upfront (matching the CLI's --payment -// default, cmd/main.go), not to Azure's raw API default (all-upfront) and +// default in the cloud-commitments-cli repo), not to Azure's raw API default (all-upfront) and // not to an error. func TestAzureComputeRecommendationFromArgsDefaultsToNoUpfront(t *testing.T) { t.Parallel() diff --git a/tools/enums.go b/tools/enums.go index 7b8157e..1760600 100644 --- a/tools/enums.go +++ b/tools/enums.go @@ -1,5 +1,5 @@ // Package tools implements the individual MCP tool handlers exposed by the -// CUDly MCP server (mcp/server.go), plus the shared validation and purchase +// CUDly MCP server (server.go), plus the shared validation and purchase // harness they all build on. package tools @@ -82,8 +82,7 @@ func (t TermYears) RecommendationTerm() string { return fmt.Sprintf("%dyr", int(t)) } -// SPType is the AWS Savings Plans product family (--include-sp-types in the -// CLI, cmd/main.go:112). +// SPType is the AWS Savings Plans product family. type SPType string const ( diff --git a/tools/list_commitment_actions.go b/tools/list_commitment_actions.go index b75db65..82f1327 100644 --- a/tools/list_commitment_actions.go +++ b/tools/list_commitment_actions.go @@ -47,7 +47,7 @@ type listCommitmentActionsTool struct { } // NewListCommitmentActions builds the cudly_list_commitment_actions tool -// from descriptors -- the same slice of Descriptor values mcp/server.go +// from descriptors -- the same slice of Descriptor values server.go // collects from every other tool's Descriptor() method, so this catalog is // generated from the live registry rather than hand-duplicated in code or // docs. @@ -56,7 +56,7 @@ func NewListCommitmentActions(descriptors []Descriptor) Registration { } // ListCommitmentActionsDescriptor returns the static Descriptor for -// cudly_list_commitment_actions itself. It is exported so mcp/server.go can +// cudly_list_commitment_actions itself. It is exported so server.go can // include this tool in its own catalog: the descriptors slice passed to // NewListCommitmentActions must be assembled (and thus known) before the // tool exists, so its own entry can't come from calling Descriptor() on an diff --git a/tools/registry.go b/tools/registry.go index 87644d7..0a93cc2 100644 --- a/tools/registry.go +++ b/tools/registry.go @@ -3,7 +3,7 @@ package tools import "github.com/modelcontextprotocol/go-sdk/mcp" // Descriptor is the source-of-truth metadata for one MCP tool. Every tool -// file builds one and both mcp/server.go (to know what to register) and +// file builds one and both server.go (to know what to register) and // cudly_list_commitment_actions (to know what to advertise) read it, so the // live tool set and the discoverability catalog can never drift apart -- // there is exactly one place each tool's name/description/example prompts @@ -85,10 +85,9 @@ func readOnlyAnnotations(title string, openWorld bool) *mcp.ToolAnnotations { // "purchasing is additive, not destructive" reading was considered and // rejected), OpenWorldHint true (every purchase reaches a live cloud // provider API), and IdempotentHint FALSE on every purchase tool, always -// (A5, 00-scope.md §6 decision register) -- even though ExecutePurchase -// derives an idempotency key from the request and dedupes an identical -// retry (mcp/tools/purchase.go), the hint can't express that conditional -// safety: idempotency_nonce is caller-supplied, so one optional string +// -- even though ExecutePurchase derives an idempotency key from the request +// and dedupes an identical retry (tools/purchase.go), the hint can't express +// that conditional safety: idempotency_nonce is caller-supplied, so one optional string // turns an otherwise-identical "safe retry" into a second real purchase, // and provider-side dedupe (AWS ClientToken, Azure/GCP equivalents) is // time- and scope-bounded, not permanent. The failure asymmetry only points