diff --git a/services/app-web/src/s3/s3Amplify.ts b/services/app-web/src/s3/s3Amplify.ts index 0b5fa71bbd..bf629d3477 100644 --- a/services/app-web/src/s3/s3Amplify.ts +++ b/services/app-web/src/s3/s3Amplify.ts @@ -99,8 +99,8 @@ function newAmplifyS3Client(bucketConfig: S3BucketConfigType): S3ClientT { }, /* Poll for scanning completion - - We start polling after 20s, which is the estimated time it takes scanning to start to resolve. - - In total, each file could be up to 40 sec in a loading state (20s wait for scanning + 8s of retries + extra time for uploading and scanning api requests to resolve) + - We start polling after 3s, which is the estimated time it takes scanning to start to resolve. + - We then retry with an exponential backoff for up to 15s. Most scans take < 1s, plus some additional time for tagging and response, so by 15s a file should be tagged. - While the file is scanning, returns 403. When scanning is complete, the resource returns 200 */ scanFile: async ( @@ -108,7 +108,7 @@ function newAmplifyS3Client(bucketConfig: S3BucketConfigType): S3ClientT { bucket: BucketShortName ): Promise => { try { - await waitFor(20000) + await waitFor(3000) try { await retryWithBackoff(async () => { await Storage.get(filename, { @@ -213,7 +213,7 @@ const waitFor = (delay = 1000) => const retryWithBackoff = async ( fn: () => Promise, retryCount = 0, - maxRetries = 6, + maxRetries = 4, err: null | S3Error = null ): Promise => { if (retryCount > maxRetries) { diff --git a/services/github-oidc/serverless.yml b/services/github-oidc/serverless.yml index 0cfbbb0e63..2f6357ab87 100644 --- a/services/github-oidc/serverless.yml +++ b/services/github-oidc/serverless.yml @@ -53,6 +53,7 @@ params: - 'kms:*' - 'lambda:*' - 'logs:*' + - 'route53:*' - 'rds:*' - 'secretsmanager:*' - 'ssm:*' diff --git a/services/postgres/serverless.yml b/services/postgres/serverless.yml index 2e516943df..1c90f7ea32 100644 --- a/services/postgres/serverless.yml +++ b/services/postgres/serverless.yml @@ -11,7 +11,7 @@ plugins: provider: name: aws - runtime: python3.7 + runtime: python3.12 region: us-east-1 iam: role: @@ -85,7 +85,7 @@ package: functions: rotator: - runtime: python3.7 + runtime: python3.12 handler: lambda_function.lambda_handler description: Conducts an AWS SecretsManager secret rotation for RDS PostgreSQL using single user rotation scheme timeout: 30 diff --git a/services/uploads/README.md b/services/uploads/README.md index 62cce27611..2df913f1a2 100644 --- a/services/uploads/README.md +++ b/services/uploads/README.md @@ -16,6 +16,32 @@ In addition to live scanning all uploaded files, we also have a pair of lambdas The avAuditUploads lambda pulls a list of every file in the uploads bucket and then invokes avAuditFiles for each of them in chunks of 20 or so. For any files that are found to be INFECTED, it then grabs the current s3 tags for them and verifies that they are tagged accordingly. If not, it will re-tag the file to be INFECTED, preventing further download. +## ClamAV Daemon + +We have an ec2 instance that is created in dev, val, and prod that is configured with an always on ClamAV instance that accepts incoming virus scan requests on port 3310. The motivation here is that we are working towards having our av scanning lambdas use the always on ClamAV daemon rather than rely on just the lambda, as there is a high startup cost for ClamAV of around 29 seconds in our testing. This means that all virus scans take at least 29 seconds for the user. By using an always on instance we can reduce that to closer to the actual time of the virus scan (usually < 1s). + +The server is restricted to only have access from connections in the default security group as well as anything else that is placed in the ClamAV security group. This allows for our AV scanning lambds to call out to the instance while restricting all other traffic. However, all of our engineers have ssh pub keys on the instance in case they need access to the machine via ssh for any reason. + +### Accessing the VM + +Similar to the [Postgres jumpbox](../postgres/README.md), we use the `authorized_keys` file to give access to this VM and you'll need to add your IP to the VM's security group: + +1. Determine your public facing IP address. An easy way to do this is to `curl https://ifconfig.me/` +2. Locate the EC2 instance in the AWS console. Click and go into Security > Security groups. +3. There should be two security groups attached to the instance, the default and the ClamAV one. Select the ClamAV security group. +4. On the `Inbound rules` tab select `Edit inbound rules` +5. Add a rule for `ssh` with the `source` set to your local IP address with `/32` appended to it (e.g. `1.2.3.4/32`) +6. Save the rule + +#### SSH to the instances + +You should now be able to ssh to the jump box. + +1. Locate the Public IPv4 address of the instance. This can be found by clicking into the VM on the `Instances` section of the EC2 console. +2. ssh ubuntu@public-ip + +You should be using public key auth to ssh. If you need to point to your private key, use `ssh -i ~/.ssh/${yourkeyfile} ubuntu@public-ip` + ## Significant dependencies - serverless-s3-upload diff --git a/services/uploads/serverless.yml b/services/uploads/serverless.yml index 0a59aee6f2..eb8002c946 100644 --- a/services/uploads/serverless.yml +++ b/services/uploads/serverless.yml @@ -52,20 +52,19 @@ provider: custom: region: ${aws:region} reactAppOtelCollectorUrl: ${env:REACT_APP_OTEL_COLLECTOR_URL, ssm:/configuration/react_app_otel_collector_url} + authorizedKeys: ${file(../postgres/scripts/authorized_keys)} webpack: webpackConfig: webpack.config.js packager: yarn packagerOptions: lockFile: ../../yarn.lock - scripts: - hooks: - # This script is run locally when running 'serverless deploy' - package:initialize: | - set -e - curl -L --output lambda_layer.zip https://github.com/CMSgov/lambda-clamav-layer/releases/download/0.7/lambda_layer.zip - deploy:finalize: | - rm lambda_layer.zip - serverless invoke --stage ${sls:stage} --function avDownloadDefinitions -t Event + vpcId: ${ssm:/configuration/${sls:stage}/vpc/id, ssm:/configuration/default/vpc/id} + sgId: ${ssm:/configuration/${sls:stage}/vpc/sg/id, ssm:/configuration/default/vpc/sg/id} + privateSubnets: + - ${ssm:/configuration/${sls:stage}/vpc/subnets/private/a/id, ssm:/configuration/default/vpc/subnets/private/a/id} + - ${ssm:/configuration/${sls:stage}/vpc/subnets/private/b/id, ssm:/configuration/default/vpc/subnets/private/b/id} + - ${ssm:/configuration/${sls:stage}/vpc/subnets/private/c/id, ssm:/configuration/default/vpc/subnets/private/c/id} + publicSubnetA: ${ssm:/configuration/${sls:stage}/vpc/subnets/public/a/id, ssm:/configuration/default/vpc/subnets/public/a/id} serverless-offline-ssm: stages: - local @@ -96,8 +95,7 @@ custom: layers: clamAv: - package: - artifact: lambda_layer.zip + path: lambda-layers-clamav functions: avScan: @@ -109,6 +107,9 @@ functions: layers: - !Ref ClamAvLambdaLayer - arn:aws:lambda:us-east-1:901920570463:layer:aws-otel-nodejs-amd64-ver-1-18-1:1 + vpc: + securityGroupIds: ${self:custom.sgId} + subnetIds: ${self:custom.privateSubnets} environment: stage: ${sls:stage} CLAMAV_BUCKET_NAME: !Ref ClamDefsBucket @@ -171,6 +172,13 @@ functions: REACT_APP_OTEL_COLLECTOR_URL: ${self:custom.reactAppOtelCollectorUrl} resources: + Conditions: + IsDevValProd: !Or + - !Equals ['${sls:stage}', 'main'] + - !Equals ['${sls:stage}', 'val'] + - !Equals ['${sls:stage}', 'prod'] + - !Equals ['${sls:stage}', 'mtscanfromlambda'] + Resources: DocumentUploadsBucket: Type: AWS::S3::Bucket @@ -364,6 +372,132 @@ resources: - !Sub ${QAUploadsBucket.Arn}/* Sid: DenyUnencryptedConnections + ClamAVSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for ClamAV daemon + VpcId: ${self:custom.vpcId} + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 3310 + ToPort: 3310 + SourceSecurityGroupId: ${self:custom.sgId} + + ClamAVInstanceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + Path: '/delegatedadmin/developer/' + Roles: + - !Ref ClamAVInstanceRole + + ClamAVInstanceRole: + Type: AWS::IAM::Role + Properties: + Path: '/delegatedadmin/developer/' + PermissionsBoundary: !Sub 'arn:aws:iam::${AWS::AccountId}:policy/cms-cloud-admin/ct-ado-poweruser-permissions-boundary-policy' + RoleName: !Sub 'clamavdVm-${sls:stage}-ServiceRole' + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ec2.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: ClamAVInstancePolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: '*' + + ClamAVInstance: + Type: AWS::EC2::Instance + Condition: IsDevValProd + Properties: + InstanceType: t3.medium + ImageId: ami-0c7217cdde317cfec # Ubuntu 22.04 LTS + IamInstanceProfile: !Ref ClamAVInstanceProfile + NetworkInterfaces: + - AssociatePublicIpAddress: true + DeviceIndex: '0' + GroupSet: + - !Ref ClamAVSecurityGroup + SubnetId: !Sub ${self:custom.publicSubnetA} + Tags: + - Key: Name + Value: clamavd-${sls:stage} + - Key: mcr-vmuse + Value: clamavd + UserData: + Fn::Base64: !Sub | + #!/bin/bash + apt-get update + apt-get install -y clamav clamav-daemon + + echo '${self:custom.authorizedKeys}' > /home/ubuntu/.ssh/authorized_keys + chown ubuntu:ubuntu /home/ubuntu/.ssh/authorized_keys + chmod 600 /home/ubuntu/.ssh/authorized_keys + + # Write to the clamd.conf + echo "TCPSocket 3310" >> /etc/clamav/clamd.conf + echo "TCPAddr 0.0.0.0" >> /etc/clamav/clamd.conf + + # Create a systemd service override to delay the start + cat < /etc/systemd/system/clamav-daemon.service.d/override.conf + [Unit] + After=network.target + EOF + + # Create a systemd service override to delay the start and set restart limits + cat < /etc/systemd/system/clamav-daemon.service.d/override.conf + [Unit] + After=network.target + StartLimitIntervalSec=1h + StartLimitBurst=5 + EOF + + # Fix the systemctl setting + sed -i 's/^StandardOutput=syslog/StandardOutput=journal/' /lib/systemd/system/clamav-daemon.service + + # Reload systemd to apply the changes + systemctl daemon-reload + + # Start clamd and get defs + systemctl enable clamav-daemon + systemctl enable clamav-freshclam + systemctl start clamav-daemon + systemctl start clamav-freshclam + + # Confirm we're up + systemctl status clamav-daemon + systemctl status clamav-freshclam + + MCRInternalZone: + Type: AWS::Route53::HostedZone + Condition: IsDevValProd + Properties: + Name: mc-review.local + VPCs: + - VPCId: ${self:custom.vpcId} + VPCRegion: !Ref AWS::Region + + ClamAVRecordSet: + Type: AWS::Route53::RecordSet + Condition: IsDevValProd + DependsOn: ClamAVInstance + Properties: + HostedZoneId: !Ref MCRInternalZone + Name: clamav.mc-review.local + Type: A + ResourceRecords: + - !GetAtt ClamAVInstance.PrivateIp + TTL: '300' + Outputs: DocumentUploadsBucketName: Value: !Ref DocumentUploadsBucket diff --git a/services/uploads/src/avLayer/build/build.sh b/services/uploads/src/avLayer/build/build.sh index addc74f5c5..0003345419 100755 --- a/services/uploads/src/avLayer/build/build.sh +++ b/services/uploads/src/avLayer/build/build.sh @@ -51,6 +51,7 @@ cp /tmp/build/usr/local/bin/clamscan /tmp/build/usr/local/bin/clamdscan /tmp/bui cp -R /tmp/build/usr/lib64/* lib/. cp -R /tmp/build/usr/local/lib64/* lib/. cp freshclam.conf bin/freshclam.conf +cp clamd.conf bin/clamd.conf zip -r9 lambda_layer.zip bin zip -r9 lambda_layer.zip lib \ No newline at end of file diff --git a/services/uploads/src/avLayer/build/clamd.conf b/services/uploads/src/avLayer/build/clamd.conf new file mode 100644 index 0000000000..0ac6deeaba --- /dev/null +++ b/services/uploads/src/avLayer/build/clamd.conf @@ -0,0 +1,12 @@ +# hostname and port of the remote ClamAV daemon +TCPAddr clamav.mc-review.local +TCPSocket 3310 + +# Enable verbose logging +LogVerbose yes + +# Path to the log file +LogFile /var/log/clamd.log + +# Set the maximum number of concurrent threads for scanning +MaxThreads 10 \ No newline at end of file diff --git a/services/uploads/src/deps/clamAV/clamAV.ts b/services/uploads/src/deps/clamAV/clamAV.ts index da3ee29aae..b50cddceed 100644 --- a/services/uploads/src/deps/clamAV/clamAV.ts +++ b/services/uploads/src/deps/clamAV/clamAV.ts @@ -21,6 +21,9 @@ interface ClamAVConfig { pathToFreshclam: string pathToConfig: string pathToDefintions: string + + pathToClamdScan: string + pathToClamdConfig: string } function NewClamAV(config: Partial, s3Client: S3UploadsClient) { @@ -36,6 +39,9 @@ function NewClamAV(config: Partial, s3Client: S3UploadsClient) { pathToFreshclam: config.pathToFreshclam || '/opt/bin/freshclam', pathToConfig: config.pathToConfig || '/opt/bin/freshclam.conf', pathToDefintions: config.pathToDefintions || '/tmp', + + pathToClamdScan: config.pathToClamdScan || '/opt/bin/clamdscan', + pathToClamdConfig: config.pathToClamdConfig || '/opt/bin/clamd.conf', } return { @@ -177,6 +183,16 @@ function scanForInfectedFiles( try { console.info('Executing clamav') + // use clamdscan to connect to our clamavd server + const avResult = spawnSync(config.pathToClamdScan, [ + '--stdout', + '-v', + `--config-file=${config.pathToClamdConfig}`, + '--stream', + pathToScan, + ]) + + /* const avResult = spawnSync(config.pathToClamav, [ '--stdout', '-v', @@ -184,6 +200,7 @@ function scanForInfectedFiles( config.pathToDefintions, pathToScan, ]) + */ console.info('stderror', avResult.stderr && avResult.stderr.toString()) console.info('stdout', avResult.stdout && avResult.stdout.toString()) diff --git a/services/uploads/src/lib/scanFiles.ts b/services/uploads/src/lib/scanFiles.ts index de1587cfe4..6723eb8f27 100644 --- a/services/uploads/src/lib/scanFiles.ts +++ b/services/uploads/src/lib/scanFiles.ts @@ -12,14 +12,6 @@ export async function scanFiles( bucket: string, scanDir: string ): Promise { - // fetch definition files - console.info('Download AV Definitions') - const defsRes = await clamAV.downloadAVDefinitions() - if (defsRes) { - console.error('failed to fetch definitions') - return defsRes - } - // clamScan wants files to be top level in the scanned directory, so we map each key to a UUID const filemap: { [filename: string]: string } = {} for (const key of keys) { diff --git a/yarn.lock b/yarn.lock index 671aa9244b..d45a89e44c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6463,10 +6463,10 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -6478,10 +6478,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@eslint/js@8.56.0": + version "8.56.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" + integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== "@floating-ui/core@^1.0.4": version "1.0.4" @@ -7463,13 +7463,13 @@ "@hapi/bourne" "^3.0.0" "@hapi/hoek" "^11.0.2" -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" minimatch "^3.0.5" "@humanwhocodes/module-importer@^1.0.1": @@ -7477,10 +7477,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -12955,6 +12955,11 @@ "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@vendia/serverless-express@^4.3.9": version "4.10.1" resolved "https://registry.yarnpkg.com/@vendia/serverless-express/-/serverless-express-4.10.1.tgz#6489cd179734f1cd690b93a90ae2e83ae8adc639" @@ -18410,17 +18415,18 @@ eslint-webpack-plugin@^3.1.1: schema-utils "^4.0.0" eslint@^8.3.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== + version "8.56.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" + integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.56.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -20937,12 +20943,7 @@ ignore@^4.0.3: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.4, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -ignore@^5.2.4, ignore@^5.3.0: +ignore@^5.0.4, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== @@ -24527,7 +24528,7 @@ minimatch@3.0.5: dependencies: brace-expansion "^1.1.7" -minimatch@9.0.3, minimatch@^9.0.1: +minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== @@ -24562,13 +24563,6 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.0.tgz#bfc8e88a1c40ffd40c172ddac3decb8451503b56" - integrity sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w== - dependencies: - brace-expansion "^2.0.1" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -30087,14 +30081,7 @@ strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== - dependencies: - ansi-regex "^6.0.1" - -strip-ansi@^7.1.0: +strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==