Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws_cdk.aws_sqs.Queue: CDK version upgrade causes grant_consume_messages to not generate IAM policy #33548

Open
1 task
rblin081 opened this issue Feb 21, 2025 · 3 comments
Labels
@aws-cdk/aws-sqs Related to Amazon Simple Queue Service bug This issue is a bug. needs-reproduction This issue needs reproduction. p2

Comments

@rblin081
Copy link

Describe the bug

When upgrading to the latest CDK version 2.179.0 there are several stack with IAM policies being dropped.

The policies are generated from using the grant_consume_message method for aws_sqs.Queue (link)

An example of the application code is

class SalesforceEventsStack(cdk.Stack):
....
        main_queue = aws_sqs.Queue(
            scope=self,
            id=queue_name,
            queue_name=f'{queue_name}-{self._honor_env.value}',
            encryption=aws_sqs.QueueEncryption.KMS,
            encryption_master_key=self._encryption_key,
            dead_letter_queue=aws_sqs.DeadLetterQueue(
                queue=dead_letter, max_receive_count=3
            ),
        )
        # sqs_worker_stack is a separate stack that owns IAM user sqs_worker_user
        main_queue.grant_consume_messages(sqs_worker_stack.sqs_worker_user)

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

2.141.0

Expected Behavior

grant_consume_messages would continue to generate IAM policies for the associated queue and grantable construct

Current Behavior

grant_consume_messages is not creating IAM policies for the IAM user / grantable construct

Reproduction Steps

Generated diff using CDK version 2.179.0

cdk diff -e SalesforceEventsStack-dev
....
Stack SalesforceEventsStack-dev
IAM Statement Changes
┌───┬──────────────────────────────────────────────────────────┬────────┬──────────────────────────────────────────────────────────┬────────────────────────────────────────────────────────────┬───────────┐
│   │ Resource                                                 │ Effect │ Action                                                   │ Principal                                                  │ Condition │
├───┼──────────────────────────────────────────────────────────┼────────┼──────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┼───────────┤
│ - │ ${salesforce-event-receiver.Arn}                         │ Allow  │ sqs:ChangeMessageVisibility                              │ AWS:arn:aws:iam::xxx:user/sqs-worker.dev          │           │
│   │                                                          │        │ sqs:DeleteMessage                                        │                                                            │           │
│   │                                                          │        │ sqs:GetQueueAttributes                                   │                                                            │           │
│   │                                                          │        │ sqs:GetQueueUrl                                          │                                                            │           │
│   │                                                          │        │ sqs:ReceiveMessage                                       │                                                            │           │
│ - │ ${salesforce-event-receiver.Arn}                         │ Allow  │ sqs:GetQueueAttributes                                   │ AWS:arn:aws:iam::xxx:user/external-webhook.dev    │           │
│   │                                                          │        │ sqs:GetQueueUrl                                          │                                                            │           │
│   │                                                          │        │ sqs:SendMessage                                          │                                                            │           │
├───┼──────────────────────────────────────────────────────────┼────────┼──────────────────────────────────────────────────────────┼────────────────────────────────────────────────────────────┼───────────┤
│ - │ ${salesforce-event-sender.Arn}                           │ Allow  │ sqs:ChangeMessageVisibility                              │ AWS:arn:aws:iam::xxx:user/sqs-worker.dev          │           │
│   │                                                          │        │ sqs:DeleteMessage                                        │                                                            │           │
│   │                                                          │        │ sqs:GetQueueAttributes                                   │                                                            │           │
│   │                                                          │        │ sqs:GetQueueUrl                                          │                                                            │           │
│   │                                                          │        │ sqs:ReceiveMessage                                       │                                                            │           │
│ - │ ${salesforce-event-sender.Arn}                           │ Allow  │ sqs:GetQueueAttributes                                   │ AWS:arn:aws:iam::xxx:user/external-api.dev        │           │
│   │                                                          │        │ sqs:GetQueueUrl                                          │                                                            │           │
│   │                                                          │        │ sqs:SendMessage                                          │                                                            │           │
└───┴──────────────────────────────────────────────────────────┴────────┴──────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┴───────────┘

Resources
[-] AWS::SQS::QueuePolicy salesforce-event-sender/Policy salesforceeventsenderPolicy03108016 destroy
[-] AWS::SQS::QueuePolicy salesforce-event-receiver/Policy salesforceeventreceiverPolicy8466F361 destroy


✨  Number of stacks with differences: 1


# Confirm version of CDK
pip show aws-cdk-lib                                         
Name: aws-cdk-lib
Version: 2.179.0

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.179.0 (build b867f19)

Framework Version

No response

Node.js Version

v18.15.0

OS

macos Sequoia version 15.2

Language

Python

Language Version

Python 3.10.6

Other information

No response

@rblin081 rblin081 added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Feb 21, 2025
@github-actions github-actions bot added the @aws-cdk/aws-sqs Related to Amazon Simple Queue Service label Feb 21, 2025
@ashishdhingra ashishdhingra self-assigned this Feb 21, 2025
@ashishdhingra ashishdhingra added p2 needs-reproduction This issue needs reproduction. and removed needs-triage This issue or PR still needs to be triaged. labels Feb 21, 2025
@ashishdhingra
Copy link
Contributor

ashishdhingra commented Feb 25, 2025

Taking below CDK code (in TypeScript) as an example:

import * as cdk from 'aws-cdk-lib';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as kms from 'aws-cdk-lib/aws-kms';

export class CdktestStackNew extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const kmsKey = new kms.Key(this, 'TestKmsKey');
    const sqsWorkerRole = new iam.Role(this, 'TestSqsWorkerRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
    });

    const mainQueue = new sqs.Queue(this, 'TestQueue', {
      queueName: 'TestQueue',
      encryption: sqs.QueueEncryption.KMS,
      encryptionMasterKey: kmsKey,
      deadLetterQueue: {
        queue: new sqs.Queue(this, 'TestDeadLetterQueue'),
        maxReceiveCount: 3
      }
    });

    mainQueue.grantConsumeMessages(sqsWorkerRole);
  }
}

Using aws-cdk-lib version 2.141.0
Running cdk synth produces the below CFN template:

Resources:
  TestKmsKeyF793768B:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Statement:
          - Action: kms:*
            Effect: Allow
            Principal:
              AWS: arn:aws:iam::<<ACCOUNT-ID>>:root
            Resource: "*"
        Version: "2012-10-17"
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: CdktestStackNew/TestKmsKey/Resource
  TestSqsWorkerRoleD45AABD6:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
    Metadata:
      aws:cdk:path: CdktestStackNew/TestSqsWorkerRole/Resource
  TestSqsWorkerRoleDefaultPolicy3CB712B5:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - sqs:ChangeMessageVisibility
              - sqs:DeleteMessage
              - sqs:GetQueueAttributes
              - sqs:GetQueueUrl
              - sqs:ReceiveMessage
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - TestQueue6F0069AA
                - Arn
          - Action: kms:Decrypt
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - TestKmsKeyF793768B
                - Arn
        Version: "2012-10-17"
      PolicyName: TestSqsWorkerRoleDefaultPolicy3CB712B5
      Roles:
        - Ref: TestSqsWorkerRoleD45AABD6
    Metadata:
      aws:cdk:path: CdktestStackNew/TestSqsWorkerRole/DefaultPolicy/Resource
  TestDeadLetterQueueB2C49D29:
    Type: AWS::SQS::Queue
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: CdktestStackNew/TestDeadLetterQueue/Resource
  TestQueue6F0069AA:
    Type: AWS::SQS::Queue
    Properties:
      KmsMasterKeyId:
        Fn::GetAtt:
          - TestKmsKeyF793768B
          - Arn
      QueueName: TestQueue
      RedrivePolicy:
        deadLetterTargetArn:
          Fn::GetAtt:
            - TestDeadLetterQueueB2C49D29
            - Arn
        maxReceiveCount: 3
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: CdktestStackNew/TestQueue/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/y2Lyw7CIBBFv6V7GEvThXuX3Sh+gEE6JpRX7BSbhvDvRnB1Tm7OHUCMAvpO7cT1bLkzT8j3TWnL1E6PbD1BnvBgl1eY8CjMKA9ZRoe/pfIandE1aFYYvQnyLWGqUZVSmESKadXt+PfCQpwRFjp9xBmGHsZuIWP4msJmPIJs/AI0SSx6pgAAAA==
    Metadata:
      aws:cdk:path: CdktestStackNew/CDKMetadata/Default
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]

Running cdk deploy:

✨  Synthesis time: 4.65s

CdktestStackNew: start: Building f8d6dd71dfddb49ed43b0319ec5e0f91b228b2455d280e604fa7a91beaf5ca36:<<ACCOUNT-ID>>-us-east-2
CdktestStackNew: success: Built f8d6dd71dfddb49ed43b0319ec5e0f91b228b2455d280e604fa7a91beaf5ca36:<<ACCOUNT-ID>>-us-east-2
CdktestStackNew: start: Publishing f8d6dd71dfddb49ed43b0319ec5e0f91b228b2455d280e604fa7a91beaf5ca36:<<ACCOUNT-ID>>-us-east-2
CdktestStackNew: success: Published f8d6dd71dfddb49ed43b0319ec5e0f91b228b2455d280e604fa7a91beaf5ca36:<<ACCOUNT-ID>>-us-east-2
Stack undefined
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬──────────────────────────┬────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────────────────────────────┬───────────┐
│   │ Resource                 │ Effect │ Action                                                                                              │ Principal                          │ Condition │
├───┼──────────────────────────┼────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────┼───────────┤
│ + │ ${TestKmsKey.Arn}        │ Allow  │ kms:*                                                                                               │ AWS:arn:aws:iam::<<ACCOUNT-ID>>:root │           │
│ + │ ${TestKmsKey.Arn}        │ Allow  │ kms:Decrypt                                                                                         │ AWS:${TestSqsWorkerRole}           │           │
├───┼──────────────────────────┼────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────┼───────────┤
│ + │ ${TestQueue.Arn}         │ Allow  │ sqs:ChangeMessageVisibility                                                                         │ AWS:${TestSqsWorkerRole}           │           │
│   │                          │        │ sqs:DeleteMessage                                                                                   │                                    │           │
│   │                          │        │ sqs:GetQueueAttributes                                                                              │                                    │           │
│   │                          │        │ sqs:GetQueueUrl                                                                                     │                                    │           │
│   │                          │        │ sqs:ReceiveMessage                                                                                  │                                    │           │
├───┼──────────────────────────┼────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────────────────────────┼───────────┤
│ + │ ${TestSqsWorkerRole.Arn} │ Allow  │ sts:AssumeRole                                                                                      │ Service:lambda.amazonaws.com       │           │
└───┴──────────────────────────┴────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────────────────┴───────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
CdktestStackNew: deploying... [1/1]
CdktestStackNew: creating CloudFormation changeset...
CdktestStackNew | 0/7 | 10:54:10 AM | REVIEW_IN_PROGRESS   | AWS::CloudFormation::Stack | CdktestStackNew User Initiated
CdktestStackNew | 0/7 | 10:54:17 AM | CREATE_IN_PROGRESS   | AWS::CloudFormation::Stack | CdktestStackNew User Initiated
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata) 
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::IAM::Role     | TestSqsWorkerRole (TestSqsWorkerRoleD45AABD6) 
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestDeadLetterQueue (TestDeadLetterQueueB2C49D29) 
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::KMS::Key      | TestKmsKey (TestKmsKeyF793768B) 
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::KMS::Key      | TestKmsKey (TestKmsKeyF793768B) Resource creation Initiated
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestDeadLetterQueue (TestDeadLetterQueueB2C49D29) Resource creation Initiated
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::IAM::Role     | TestSqsWorkerRole (TestSqsWorkerRoleD45AABD6) Resource creation Initiated
CdktestStackNew | 0/7 | 10:54:19 AM | CREATE_IN_PROGRESS   | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata) Resource creation Initiated
CdktestStackNew | 1/7 | 10:54:20 AM | CREATE_COMPLETE      | AWS::CDK::Metadata | CDKMetadata/Default (CDKMetadata) 
CdktestStackNew | 1/7 | 10:54:20 AM | CREATE_IN_PROGRESS   | AWS::KMS::Key      | TestKmsKey (TestKmsKeyF793768B) Eventual consistency check initiated
CdktestStackNew | 1/7 | 10:54:20 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestDeadLetterQueue (TestDeadLetterQueueB2C49D29) Eventual consistency check initiated
CdktestStackNew | 1/7 | 10:54:21 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestQueue (TestQueue6F0069AA) 
CdktestStackNew | 1/7 | 10:54:21 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestQueue (TestQueue6F0069AA) Resource creation Initiated
CdktestStackNew | 1/7 | 10:54:22 AM | CREATE_IN_PROGRESS   | AWS::SQS::Queue    | TestQueue (TestQueue6F0069AA) Eventual consistency check initiated
CdktestStackNew | 2/7 | 10:54:35 AM | CREATE_COMPLETE      | AWS::KMS::Key      | TestKmsKey (TestKmsKeyF793768B) 
CdktestStackNew | 3/7 | 10:54:36 AM | CREATE_COMPLETE      | AWS::IAM::Role     | TestSqsWorkerRole (TestSqsWorkerRoleD45AABD6) 
CdktestStackNew | 3/7 | 10:54:36 AM | CREATE_IN_PROGRESS   | AWS::IAM::Policy   | TestSqsWorkerRole/DefaultPolicy (TestSqsWorkerRoleDefaultPolicy3CB712B5) 
CdktestStackNew | 3/7 | 10:54:37 AM | CREATE_IN_PROGRESS   | AWS::IAM::Policy   | TestSqsWorkerRole/DefaultPolicy (TestSqsWorkerRoleDefaultPolicy3CB712B5) Resource creation Initiated
CdktestStackNew | 4/7 | 10:54:50 AM | CREATE_COMPLETE      | AWS::SQS::Queue    | TestDeadLetterQueue (TestDeadLetterQueueB2C49D29) 
CdktestStackNew | 5/7 | 10:54:52 AM | CREATE_COMPLETE      | AWS::SQS::Queue    | TestQueue (TestQueue6F0069AA) 
CdktestStackNew | 6/7 | 10:54:53 AM | CREATE_COMPLETE      | AWS::IAM::Policy   | TestSqsWorkerRole/DefaultPolicy (TestSqsWorkerRoleDefaultPolicy3CB712B5) 
CdktestStackNew | 7/7 | 10:54:53 AM | CREATE_COMPLETE      | AWS::CloudFormation::Stack | CdktestStackNew 

 ✅  CdktestStackNew

✨  Deployment time: 45.63s

Stack ARN:
arn:aws:cloudformation:us-east-2:<<ACCOUNT-ID>>:stack/CdktestStackNew/10860650-f473-11ef-8172-06a121b83cf3

✨  Total time: 50.28s

Upgrading to aws-cdk-lib version 2.180.0
Running cdk synth generates the below CFN template:

Resources:
  TestKmsKeyF793768B:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Statement:
          - Action: kms:*
            Effect: Allow
            Principal:
              AWS: arn:aws:iam::<<ACCOUNT-ID>>:root
            Resource: "*"
        Version: "2012-10-17"
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: CdktestStackNew/TestKmsKey/Resource
  TestSqsWorkerRoleD45AABD6:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
    Metadata:
      aws:cdk:path: CdktestStackNew/TestSqsWorkerRole/Resource
  TestSqsWorkerRoleDefaultPolicy3CB712B5:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - sqs:ChangeMessageVisibility
              - sqs:DeleteMessage
              - sqs:GetQueueAttributes
              - sqs:GetQueueUrl
              - sqs:ReceiveMessage
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - TestQueue6F0069AA
                - Arn
          - Action: kms:Decrypt
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - TestKmsKeyF793768B
                - Arn
        Version: "2012-10-17"
      PolicyName: TestSqsWorkerRoleDefaultPolicy3CB712B5
      Roles:
        - Ref: TestSqsWorkerRoleD45AABD6
    Metadata:
      aws:cdk:path: CdktestStackNew/TestSqsWorkerRole/DefaultPolicy/Resource
  TestDeadLetterQueueB2C49D29:
    Type: AWS::SQS::Queue
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: CdktestStackNew/TestDeadLetterQueue/Resource
  TestQueue6F0069AA:
    Type: AWS::SQS::Queue
    Properties:
      KmsMasterKeyId:
        Fn::GetAtt:
          - TestKmsKeyF793768B
          - Arn
      QueueName: TestQueue
      RedrivePolicy:
        deadLetterTargetArn:
          Fn::GetAtt:
            - TestDeadLetterQueueB2C49D29
            - Arn
        maxReceiveCount: 3
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: CdktestStackNew/TestQueue/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAA/yWKyw6CMBAAv4X7di3EA3ePXBQ+wNSyJqWvyFIJafrvxnKayWQ6bHuJslE7Cz1b4cwL87QpbUHt/MzWM+aBDri9w0BHAaM85jE6+pfKe3RG1+G0AvxhzI9EqU5VSoGROKZVU4EQZ8KFL9+2x07itVnYGLGmsBlPOJ78AcGqfXSaAAAA
    Metadata:
      aws:cdk:path: CdktestStackNew/CDKMetadata/Default
Parameters:
  BootstrapVersion:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /cdk-bootstrap/hnb659fds/version
    Description: Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]

Running cdk diff:

start: Building 4a219e64c8aed159d5b8319aca9e99397d70b9709304c8430d9c6a77af17f70d:<<ACCOUNT-ID>>-us-east-2
success: Built 4a219e64c8aed159d5b8319aca9e99397d70b9709304c8430d9c6a77af17f70d:<<ACCOUNT-ID>>-us-east-2
start: Publishing 4a219e64c8aed159d5b8319aca9e99397d70b9709304c8430d9c6a77af17f70d:<<ACCOUNT-ID>>-us-east-2
success: Published 4a219e64c8aed159d5b8319aca9e99397d70b9709304c8430d9c6a77af17f70d:<<ACCOUNT-ID>>-us-east-2
Hold on while we create a read-only change set to get a diff with accurate replacement information (use --no-change-set to use a less accurate but faster template-only diff)
Stack CdktestStackNew
There were no differences

✨  Number of stacks with differences: 0

@rblin081 Good morning. Could you please share the self contained reproducible code and steps to troubleshoot the issue? Also share the output of cdk synth for both CDK version 2.141.0 and 2.179.0.

In your code, sqs_worker_stack is a separate stack that owns IAM user sqs_worker_user. Is it possible that the other stack changed any user property or it's name?

Thanks,
Ashish

@ashishdhingra ashishdhingra added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Feb 26, 2025
Copy link

This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Feb 27, 2025
@rgoltz
Copy link

rgoltz commented Feb 28, 2025

Comment since Bot is too fast here...

@github-actions github-actions bot removed closing-soon This issue will automatically close in 4 days unless further comments are made. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Feb 28, 2025
@ashishdhingra ashishdhingra removed their assignment Mar 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-sqs Related to Amazon Simple Queue Service bug This issue is a bug. needs-reproduction This issue needs reproduction. p2
Projects
None yet
Development

No branches or pull requests

3 participants