Skip to content
Expert Cloud & AI
Menu

From specification to AWS: inside an AI-assisted migration

A practical delivery workflow with AWS architecture, bounded agent tasks, permission checks and promotion of the tested artifact.

Chris Baran

· 5 min read

On this page
  1. Give the agent a contract before giving it a task
  2. Separate the request path from the delivery path
  3. Express one network boundary in code
  4. Authenticate identity, then authorise the operation
  5. Approve the artifact that passed the checks
  6. Show the boundary by testing rejection
  7. Follow the work beyond its first implementation

The business companion describes modernising an existing service through structured AI-assisted delivery. This article examines the mechanics: a bounded task, a defined AWS architecture, an application permission check and a release decision tied to the tested artifact.

For an oil and gas company, one engineer brought the application changes, AWS infrastructure and deployment workflow together over three weeks. The diagram and code below use a fictional service to explain the architecture and controls.

Give the agent a contract before giving it a task

An implementation task needs an observable finish. “Improve authentication” is too open-ended. A useful task names a behaviour, a change boundary and evidence that a reviewer can examine.

An illustrative implementation brief
task: enforce-export-permission
change_boundary:
  - application permission check
  - tests for allowed and rejected requests
precondition:
  - identity has been verified by trusted middleware
acceptance:
  - a permitted principal can request an export
  - an authenticated principal without permission is rejected
  - an absent principal is rejected
outside_scope:
  - identity-provider configuration
  - deployment credentials
  - production release

The Superpowers framework provides a way to organise specifications, plans, implementation tasks and review. We used that approach to define the specification and break the implementation into bounded tasks. The value comes from connecting each task to its acceptance evidence and reviewing the resulting change.

Instructions are part of that workflow, but access restrictions need enforcement outside the prompt. The agent performing this example task does not need a production credential or permission to change the identity provider.

Separate the request path from the delivery path

A reference service might use an internal Application Load Balancer, an ECS Fargate workload and an image held in ECR. The application receives requests through a defined entry point. A separate pipeline builds, tests and promotes its image.

100%
Reference architecture showing a user reaching an authenticated load balancer and application, with a separate build, check and approval path supplying the container image.

Illustrative architecture. Request access and release authority are separate decisions; this is not a client network diagram.

Illustrative architecture. Request access and release authority are separate decisions; this is not a client network diagram.

Keep the responsibilities clear. The load balancer handles the configured entry path and authentication flow. The application decides whether an authenticated principal may perform an operation. The task’s AWS role controls its AWS API access. The pipeline’s deployment role controls releases.

AWS distinguishes the task execution role, used for platform activities such as pulling images and writing logs, from the task role used by application code. Giving each its required permissions keeps those responsibilities explicit. AWS guidance on ECS IAM roles.

Express one network boundary in code

For a workload with an HTTPS listener on port 443, this CloudFormation resource fragment admits that port from a designated load-balancer security group:

One ingress rule, not a complete stack
Type: AWS::EC2::SecurityGroupIngress
Properties:
  GroupId:
    Ref: ApplicationSecurityGroup
  SourceSecurityGroupId:
    Ref: LoadBalancerSecurityGroup
  IpProtocol: tcp
  FromPort: 443
  ToPort: 443

The group references avoid granting access to an entire address range merely because the workload lives on a private network. This is a source-security-group rule: other resources associated with that source group can also satisfy it. Group membership therefore matters. AWS documents this pattern for services behind an ALB. ECS network security guidance.

The fragment grants one ingress path. Other attached rules, egress, routes, certificates and the application listener still require configuration and review. Declaring port 443 does not itself enable TLS. Our illustrative test checks the generated resource’s source and port range; a deployed check must separately verify reachability and the intended encryption behaviour.

Authenticate identity, then authorise the operation

An authenticated user may still lack permission to export a report. This small application check makes that distinction visible:

requirePermission — from controls.ts
// requirePermission runs application-level authorisation only after trusted
// middleware has cryptographically verified identity. It cannot establish trust.
 
export type VerifiedPrincipal = {
  subject: string;
  permissions: readonly string[];
};
 
export function requirePermission(
  principal: VerifiedPrincipal | null,
  permission: string,
): void {
  if (principal === null || principal.subject.trim().length === 0) {
    throw new Error("Unauthenticated");
  }
  if (permission.trim().length === 0) {
    throw new Error("Forbidden");
  }
  if (!principal.permissions.includes(permission)) {
    throw new Error("Forbidden");
  }
}

The precondition matters. VerifiedPrincipal is a TypeScript contract, not cryptographic proof. Trusted middleware must establish the principal; request JSON must never be allowed to manufacture it.

If an ALB supplies identity claims, follow AWS’s verification requirements for its signed claims, including checking the expected signer. An ordinary user-controlled header is not a trusted principal. Keep the application reachable only through the intended path and retain the application’s operation-level permission checks. ALB authentication and signature verification.

The example tests cover a permitted user, a user missing the required permission and an absent identity. They verify the application decision rule. They do not test an identity provider, token verification library or deployed load balancer.

Approve the artifact that passed the checks

A release process needs a stable answer to “what did we test?” Build an image, identify it by digest, and carry that identity through verification and approval. Avoid rebuilding a supposedly equivalent image after approval.

The following decision rule requires the proposed artifact and the approved artifact to match the tested digest:

canPromote — from controls.ts
// canPromote evaluates promotion evidence from trusted CI/approval systems;
// it is the decision rule, not the system authenticating evidence.
 
export type PromotionEvidence = {
  testedDigest: string;
  proposedDigest: string;
  checksPassed: boolean;
  approvedDigest: string;
};
 
function isValidSha256(digest: string): boolean {
  return /^sha256:[a-f0-9]{64}$/.test(digest);
}
 
export function canPromote(evidence: PromotionEvidence): boolean {
  if (!isValidSha256(evidence.testedDigest)) return false;
  if (evidence.checksPassed !== true) return false;
  if (evidence.proposedDigest !== evidence.testedDigest) return false;
  if (evidence.approvedDigest !== evidence.testedDigest) return false;
  return true;
}

The surrounding CI system must establish the evidence. It must protect the test result, bind approval to the artifact and restrict who can use the deployment role. A caller that can fabricate all three inputs can bypass a pure function; this example deliberately isolates the comparison being tested.

An ECR repository can also prevent selected image tags from being overwritten. That is useful protection around naming, while the release record should retain the exact image digest. ECR tag immutability.

In a practical pipeline the sequence is build → test → record digest → review → deploy that digest → verify the service. A failed check must block promotion. A health check confirms a particular service response; functional acceptance, access checks and a recovery decision remain separate requirements.

Show the boundary by testing rejection

The companion examples include rejection cases that correspond to the decisions above:

Test caseExpected resultWhat it demonstrates
Principal has the required permissionApplication check returnsThe permitted path works
Principal lacks that permissionApplication check throwsSign-in alone cannot satisfy this operation check
Proposed image differs from tested imagePromotion returns falseThe decision rule detects an artifact substitution
Approval names a different digestPromotion returns falseApproval is tied to the artifact being considered
Application and load-balancer group IDs are identicalRule builder throwsThe example cannot silently turn the intended two-group boundary into a self-reference

Run the companion tests with Vitest. They use fictional identifiers and make no AWS calls. The example code, tests and README are available below; they are small decision rules rather than a deployable application.

Download the example code · Download the tests · Read the example notes

Follow the work beyond its first implementation

One engineer delivered the application, authentication, infrastructure and deployment changes over three weeks. The work progressed from design and initial implementation into integration and application refinement, bringing the service and its AWS delivery process together.

AI supported the bounded implementation tasks, while the engineer directed the architecture, security requirements and review. The result was a repeatable delivery workflow for the service, with the design and verification steps available for the next person to maintain it.

The result is a practical way to use AI in enterprise engineering: small contracts, explicit authority, code that expresses the important decisions and evidence that another person can inspect. The next article applies the same discipline to model-generated research and its sources.