├── .devcontainer └── devcontainer.json ├── .dockerignore ├── .editorconfig ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── auto-assign.yaml │ ├── codeql.yaml │ ├── dependabot-reviewer.yaml │ ├── feature.yaml │ ├── first-release.yaml │ ├── hotfix.yaml │ ├── main.yaml │ ├── release.yaml │ ├── rollback.yaml │ ├── techdocs.yaml │ └── trivy-code.yaml ├── .gitignore ├── .vscode └── launch.json ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── README.md ├── RELEASE.md ├── SECURITY.md ├── app ├── .dockerignore ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .yarnrc ├── README.md ├── app-config.production.yaml ├── app-config.yaml ├── backstage.json ├── catalog-info.yaml ├── devspace_start.sh ├── examples │ ├── entities.yaml │ ├── org.yaml │ └── template │ │ ├── content │ │ ├── catalog-info.yaml │ │ ├── index.js │ │ └── package.json │ │ └── template.yaml ├── lerna.json ├── package.json ├── packages │ ├── README.md │ ├── app │ │ ├── .eslintignore │ │ ├── .eslintrc.js │ │ ├── e2e-tests │ │ │ └── app.test.ts │ │ ├── package.json │ │ ├── public │ │ │ ├── android-chrome-192x192.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── manifest.json │ │ │ ├── robots.txt │ │ │ └── safari-pinned-tab.svg │ │ └── src │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── apis.ts │ │ │ ├── components │ │ │ ├── Root │ │ │ │ ├── LogoFull.tsx │ │ │ │ ├── LogoIcon.tsx │ │ │ │ ├── Root.tsx │ │ │ │ └── index.ts │ │ │ ├── catalog │ │ │ │ └── EntityPage.tsx │ │ │ └── search │ │ │ │ └── SearchPage.tsx │ │ │ ├── index.tsx │ │ │ └── setupTests.ts │ └── backend │ │ ├── .eslintrc.js │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── package.json │ │ └── src │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── metrics.ts │ │ ├── plugins │ │ ├── app.ts │ │ ├── auth.ts │ │ ├── catalog.ts │ │ ├── healthcheck.ts │ │ ├── kubernetes.ts │ │ ├── proxy.ts │ │ ├── scaffolder.ts │ │ ├── search.ts │ │ ├── sonarqube.ts │ │ ├── techdocs.ts │ │ └── todo.ts │ │ └── types.ts ├── playwright.config.ts ├── plugins │ └── README.md ├── tsconfig.json └── yarn.lock ├── catalog-info.yaml ├── devspace.yaml ├── docker-compose.yml ├── docs └── index.md ├── mkdocs.yml └── techstack.yml /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Node.js Core Developer Environment", 3 | "extensions": [ 4 | "github.vscode-pull-request-github", 5 | "ms-vsliveshare.vsliveshare", 6 | "vscode-icons-team.vscode-icons", 7 | "visualstudioexptteam.vscodeintellicode" 8 | ], 9 | "image": "nodejs/devcontainer:nightly", 10 | "initializeCommand": "docker system prune -f -a", 11 | "settings": { 12 | "terminal.integrated.profiles.linux": { 13 | "zsh (login)": { 14 | "path": "zsh", 15 | "args": [ 16 | "-l" 17 | ] 18 | } 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | app/packages/*/node_modules 3 | app/packages/*/dist 4 | app/dist-types 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | indent_style = space 12 | 13 | [*.html] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.{ts,json,js,tsx,jsx}] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.md] 22 | indent_size = 2 23 | indent_style = space 24 | 25 | [Dockerfile] 26 | indent_style = space 27 | indent_size = 2 28 | 29 | [*.{yml,yaml}] 30 | indent_size = 2 31 | indent_style = space 32 | end_of_line = lf 33 | charset = utf-8 34 | trim_trailing_whitespace = true 35 | insert_final_newline = false 36 | line_wrap_mode = soft wrap 37 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | * @devxp-tech/sre-team 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Thank you for making `devxp-tech/backstage` better 2 | 3 | ## What kind of change does this PR introduce? 4 | 5 | * [ ] Bugfix 6 | * [ ] Feature 7 | * [ ] Code style update (formatting) 8 | * [ ] Refactoring (no functional changes) 9 | * [ ] CI related changes 10 | * [ ] Other... Please describe: 11 | 12 | ## What is the current behavior? 13 | 14 | 15 | ## What is the new behavior? 16 | 17 | 18 | ## Does this PR introduce a new API versioning or breaking change? 19 | 20 | * [ ] Yes 21 | * [ ] No 22 | 23 | 24 | 25 | ## Other information 26 | ## Also verify you have: 27 | 28 | * [ ] Read the [contributions](../CONTRIBUTING.md) page. 29 | * [ ] Read the [DCO](../DCO), if you are a first time contributor. 30 | * [ ] Read the [code of conduct]([Code of Conduct](https://github.com/devxp-tech/.github/blob/main/CODE_OF_CONDUCT.md)). 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: /app 5 | target-branch: "hotfix/dependabot" 6 | open-pull-requests-limit: 10 7 | schedule: 8 | interval: daily 9 | - package-ecosystem: github-actions 10 | directory: .github/ 11 | target-branch: "hotfix/dependabot" 12 | open-pull-requests-limit: 10 13 | schedule: 14 | interval: daily -------------------------------------------------------------------------------- /.github/workflows/auto-assign.yaml: -------------------------------------------------------------------------------- 1 | name: Auto Assign 🦾 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | pull_request: 7 | types: [opened] 8 | 9 | jobs: 10 | auto-assign: 11 | uses: devxp-tech/.github/.github/workflows/auto-assign.yaml@main 12 | secrets: inherit 13 | with: 14 | assignees: diegoluisi 15 | numOfAssignee: 1 -------------------------------------------------------------------------------- /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | name: CodeQL 🔎 2 | 3 | on: 4 | schedule: 5 | - cron: '30 6 * * *' 6 | 7 | jobs: 8 | env: 9 | uses: devxp-tech/.github/.github/workflows/codeql.yaml@main 10 | with: 11 | language: javascript 12 | permissions: 13 | actions: read 14 | contents: read 15 | security-events: write -------------------------------------------------------------------------------- /.github/workflows/dependabot-reviewer.yaml: -------------------------------------------------------------------------------- 1 | name: Dependabot Reviewer 🤖 2 | 3 | on: pull_request_target 4 | 5 | permissions: 6 | pull-requests: write 7 | contents: write 8 | 9 | jobs: 10 | review-dependabot-pr: 11 | runs-on: ubuntu-latest 12 | if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }} 13 | steps: 14 | - name: Dependabot metadata 15 | id: dependabot-metadata 16 | uses: dependabot/fetch-metadata@v1.4.0 17 | 18 | # - name: Enable Pull Request Automerge 19 | # run: gh pr merge --merge --auto "1" 20 | # env: 21 | # GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 22 | 23 | - name: Enable auto-merge for Dependabot PRs 24 | # run: gh pr merge --auto --merge "$PR_URL" 25 | run: gh pr merge --auto -s "$PR_URL" 26 | env: 27 | PR_URL: ${{github.event.pull_request.html_url}} 28 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 29 | 30 | - name: Approve patch and minor updates 31 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch' || steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor'}} 32 | run: gh pr review $PR_URL --approve -b "I'm **approving** this pull request because **it includes a patch or minor update**" 33 | env: 34 | PR_URL: ${{github.event.pull_request.html_url}} 35 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 36 | 37 | - name: Approve major updates of development dependencies 38 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-major' && steps.dependabot-metadata.outputs.dependency-type == 'direct:development'}} 39 | run: gh pr review $PR_URL --approve -b "I'm **approving** this pull request because **it includes a major update of a dependency used only in development**" 40 | env: 41 | PR_URL: ${{github.event.pull_request.html_url}} 42 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 43 | 44 | - name: Comment on major updates of non-development dependencies 45 | if: ${{steps.dependabot-metadata.outputs.update-type == 'version-update:semver-major' && steps.dependabot-metadata.outputs.dependency-type == 'direct:production'}} 46 | run: | 47 | gh pr comment $PR_URL --body "I'm **not approving** this PR because **it includes a major update of a dependency used in production**" 48 | gh pr edit $PR_URL --add-label "requires-manual-qa" 49 | env: 50 | PR_URL: ${{github.event.pull_request.html_url}} 51 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 52 | -------------------------------------------------------------------------------- /.github/workflows/feature.yaml: -------------------------------------------------------------------------------- 1 | name: Feature ✨ 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'feature/**' 7 | paths-ignore: 8 | - README.md 9 | - catalog-info.yaml 10 | - 'docs/**' 11 | 12 | jobs: 13 | env: 14 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 15 | 16 | test: 17 | uses: devxp-tech/.github/.github/workflows/test.yaml@main 18 | needs: 19 | - env 20 | 21 | quality-gate: 22 | uses: devxp-tech/.github/.github/workflows/sonarqube.yaml@main 23 | secrets: inherit 24 | needs: 25 | - env 26 | 27 | code-scan: 28 | uses: devxp-tech/.github/.github/workflows/synk-golang.yaml@main 29 | secrets: inherit 30 | needs: 31 | - env 32 | 33 | notify: 34 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 35 | if: always() 36 | secrets: inherit 37 | needs: 38 | - env 39 | - test 40 | - quality-gate 41 | - code-scan 42 | # - action-pull-request -------------------------------------------------------------------------------- /.github/workflows/first-release.yaml: -------------------------------------------------------------------------------- 1 | name: First Release 🌱 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'first-release/*' 7 | 8 | jobs: 9 | env: 10 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 11 | 12 | test: 13 | uses: devxp-tech/.github/.github/workflows/test.yaml@main 14 | 15 | quality-gate: 16 | uses: devxp-tech/.github/.github/workflows/sonarqube.yaml@main 17 | secrets: inherit 18 | 19 | docs: 20 | uses: devxp-tech/.github/.github/workflows/techdocs.yaml@main 21 | secrets: inherit 22 | with: 23 | repository: ${{ needs.env.outputs.repository }} 24 | needs: 25 | - env 26 | 27 | build-and-push: 28 | uses: devxp-tech/.github/.github/workflows/build-and-push.yaml@main 29 | with: 30 | tag: ${{ needs.env.outputs.tag }} 31 | needs: 32 | - env 33 | - test 34 | - quality-gate 35 | 36 | security-gateway: 37 | uses: devxp-tech/.github/.github/workflows/trivy.yaml@main 38 | with: 39 | tag: ${{ needs.env.outputs.tag }} 40 | needs: 41 | - env 42 | - build-and-push 43 | 44 | deploy: 45 | uses: devxp-tech/.github/.github/workflows/deploy.yaml@main 46 | secrets: inherit 47 | with: 48 | tag: ${{ needs.env.outputs.tag }} 49 | repository: ${{ needs.env.outputs.repository }} 50 | url: https://${{ needs.env.outputs.repository }}.devxp-tech.io 51 | environment: development 52 | needs: 53 | - env 54 | - security-gateway 55 | 56 | promote: 57 | uses: devxp-tech/.github/.github/workflows/promote.yaml@main 58 | secrets: inherit 59 | with: 60 | tag: ${{ needs.env.outputs.tag }} 61 | repository: ${{ needs.env.outputs.repository }} 62 | url: https://${{ needs.env.outputs.repository }}.devxp-tech.io 63 | environment: production 64 | needs: 65 | - env 66 | - deploy 67 | 68 | notify: 69 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 70 | if: always() 71 | secrets: inherit 72 | needs: 73 | - promote -------------------------------------------------------------------------------- /.github/workflows/hotfix.yaml: -------------------------------------------------------------------------------- 1 | name: HotFix 🔥 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'hotfix/**' 7 | paths-ignore: 8 | - README.md 9 | - catalog-info.yaml 10 | - 'docs/**' 11 | 12 | jobs: 13 | env: 14 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 15 | 16 | test: 17 | uses: devxp-tech/.github/.github/workflows/test.yaml@main 18 | 19 | quality-gate: 20 | uses: devxp-tech/.github/.github/workflows/sonarqube.yaml@main 21 | secrets: inherit 22 | 23 | code-scan: 24 | uses: devxp-tech/.github/.github/workflows/synk-golang.yaml@main 25 | secrets: inherit 26 | 27 | build-and-push: 28 | uses: devxp-tech/.github/.github/workflows/build-and-push.yaml@main 29 | with: 30 | tag: ${{ needs.env.outputs.tag }} 31 | needs: 32 | - env 33 | - test 34 | # - quality-gate 35 | - code-scan 36 | 37 | security-gateway: 38 | uses: devxp-tech/.github/.github/workflows/trivy.yaml@main 39 | with: 40 | tag: ${{ needs.env.outputs.tag }} 41 | needs: 42 | - env 43 | - build-and-push 44 | 45 | deploy: 46 | uses: devxp-tech/.github/.github/workflows/deploy.yaml@main 47 | secrets: inherit 48 | with: 49 | tag: ${{ needs.env.outputs.tag }} 50 | repository: ${{ needs.env.outputs.repository }} 51 | url: https://${{ needs.env.outputs.repository }}.devxp-tech.io 52 | environment: development 53 | needs: 54 | - env 55 | - security-gateway 56 | 57 | notify: 58 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 59 | if: always() 60 | secrets: inherit 61 | needs: 62 | - deploy 63 | -------------------------------------------------------------------------------- /.github/workflows/main.yaml: -------------------------------------------------------------------------------- 1 | name: Main 🚀 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths-ignore: 8 | - 'README.md' 9 | - 'mkdocs.yml' 10 | - 'docs/**' 11 | - 'catalog-info.yaml' 12 | 13 | jobs: 14 | env: 15 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 16 | 17 | promote: 18 | uses: devxp-tech/.github/.github/workflows/promote.yaml@main 19 | secrets: inherit 20 | with: 21 | tag: ${{ needs.env.outputs.tag }} 22 | repository: ${{ needs.env.outputs.repository }} 23 | url: https://${{ needs.env.outputs.repository }}.devxp-tech.io 24 | environment: production 25 | needs: 26 | - env 27 | 28 | notify: 29 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 30 | if: always() 31 | secrets: inherit 32 | needs: 33 | - promote 34 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 📦 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'release/**' 7 | paths-ignore: 8 | - README.md 9 | - catalog-info.yaml 10 | - 'docs/**' 11 | 12 | env: 13 | ENVIRONMENT: development 14 | 15 | jobs: 16 | env: 17 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 18 | 19 | build-and-push: 20 | uses: devxp-tech/.github/.github/workflows/build-and-push.yaml@main 21 | with: 22 | tag: ${{ needs.env.outputs.tag }} 23 | needs: 24 | - env 25 | 26 | security-gateway: 27 | uses: devxp-tech/.github/.github/workflows/trivy.yaml@main 28 | with: 29 | tag: ${{ needs.env.outputs.tag }} 30 | needs: 31 | - env 32 | - build-and-push 33 | 34 | release: 35 | uses: devxp-tech/.github/.github/workflows/create-release.yaml@main 36 | secrets: inherit 37 | with: 38 | tag: ${{ needs.env.outputs.tag }} 39 | needs: 40 | - env 41 | - security-gateway 42 | 43 | deploy: 44 | uses: devxp-tech/.github/.github/workflows/deploy.yaml@main 45 | secrets: inherit 46 | with: 47 | tag: ${{ needs.env.outputs.tag }} 48 | repository: ${{ needs.env.outputs.repository }} 49 | url: https://${{ needs.env.outputs.repository }}.devxp-tech.io 50 | environment: development 51 | needs: 52 | - env 53 | - security-gateway 54 | - release 55 | 56 | notify: 57 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 58 | if: always() 59 | secrets: inherit 60 | needs: 61 | - deploy -------------------------------------------------------------------------------- /.github/workflows/rollback.yaml: -------------------------------------------------------------------------------- 1 | name: Rollback 🔙 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag: 7 | description: "Set Docker Image Tag to RollBack" 8 | required: true 9 | 10 | jobs: 11 | env: 12 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 13 | 14 | rollback: 15 | uses: devxp-tech/.github/.github/workflows/rollback.yaml@main 16 | secrets: inherit 17 | with: 18 | tag: ${{ inputs.tag }} 19 | repository: ${{ needs.env.outputs.repository }} 20 | needs: 21 | - env 22 | 23 | notify: 24 | uses: devxp-tech/.github/.github/workflows/notify.yaml@main 25 | if: always() 26 | secrets: inherit 27 | needs: 28 | - rollback -------------------------------------------------------------------------------- /.github/workflows/techdocs.yaml: -------------------------------------------------------------------------------- 1 | name: TechDocs 📚 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | # You can even set it to run only when TechDocs related files are updated. 7 | paths: 8 | - "docs/**" 9 | - "mkdocs.yml" 10 | 11 | jobs: 12 | env: 13 | uses: devxp-tech/.github/.github/workflows/env.yaml@main 14 | 15 | docs: 16 | uses: devxp-tech/.github/.github/workflows/techdocs.yaml@main 17 | secrets: inherit 18 | with: 19 | repository: ${{ needs.env.outputs.repository }} 20 | needs: 21 | - env -------------------------------------------------------------------------------- /.github/workflows/trivy-code.yaml: -------------------------------------------------------------------------------- 1 | name: Code Scanning 🔎 2 | 3 | on: 4 | schedule: 5 | - cron: '30 6 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | trivy-Scan: 10 | uses: devxp-tech/.github/.github/workflows/trivy-code.yaml@main -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app_old/ 2 | .devspace/ 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Start Backend", 3 | "type": "node", 4 | "request": "launch", 5 | "args": [ 6 | "package", 7 | "start" 8 | ], 9 | "cwd": "${workspaceFolder}/app/packages/backend", 10 | "program": "${workspaceFolder}/app/node_modules/.bin/backstage-cli", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "console": "integratedTerminal" 15 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Code of Conduct 2 | 3 | Backstage follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # this layer is only for development 2 | FROM node:20 AS base 3 | RUN apt update && apt upgrade -y && npm i -g npm yarn --force 4 | RUN apt install -y python3 g++ build-essential 5 | RUN yarn config set python $(which python3) 6 | # dev layer include git cli 7 | FROM base AS dev 8 | RUN apt install git -y 9 | # build layer responsible to build app 10 | FROM dev AS build 11 | WORKDIR /app 12 | COPY app/ . 13 | RUN yarn install && yarn tsc && yarn build:backend 14 | 15 | # original docker file section 16 | FROM node:20-bookworm-slim AS shippment 17 | 18 | # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. 19 | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 20 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 21 | apt-get update && \ 22 | apt-get install -y --no-install-recommends python3 g++ build-essential && \ 23 | yarn config set python /usr/bin/python3 24 | 25 | # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, 26 | # in which case you should also move better-sqlite3 to "devDependencies" in package.json. 27 | # RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 28 | # --mount=type=cache,target=/var/lib/apt,sharing=locked \ 29 | # apt-get update && \ 30 | # apt-get install -y --no-install-recommends libsqlite3-dev 31 | 32 | # From here on we use the least-privileged `node` user to run the backend. 33 | USER node 34 | 35 | # This should create the app dir AS `node`. 36 | # If it is instead created AS `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. 37 | # If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created AS `node`. 38 | WORKDIR /app 39 | 40 | # This switches many Node.js dependencies to production mode. 41 | ENV NODE_ENV production 42 | 43 | # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. 44 | # The skeleton contains the package.json of each package in the monorepo, 45 | # and along with yarn.lock and the root package.json, that's enough to run yarn install. 46 | COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton.tar.gz ./ 47 | RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz 48 | 49 | RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ 50 | yarn install --frozen-lockfile --production --network-timeout 300000 51 | 52 | # Then copy the rest of the backend bundle, along with any other files we might want. 53 | COPY --from=build --chown=node:node /app/packages/backend/dist/bundle.tar.gz /app/app-config*.yaml ./ 54 | RUN tar xzf bundle.tar.gz && rm bundle.tar.gz 55 | 56 | CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Diego Luisi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Backstage 2 | 3 | [![main](https://github.com/devxp-tech/backstage/actions/workflows/main.yaml/badge.svg)](https://github.com/devxp-tech/backstage/actions/workflows/main.yaml) 4 | [![Quality Gate Status](https://sonar.devxp-tech.io/api/project_badges/measure?project=backstage&metric=alert_status&token=sqb_75874b86dd51377e19e0a63680ce408a315f5327)](https://sonar.devxp-tech.io/dashboard?id=backstage) 5 | [![App Status](https://argocd.devxp-tech.io/api/badge?name=backstage-prd&revision=true)](https://argocd.devxp-tech.io/applications/backstage-prd) 6 | 7 | ## Backstage - IDP 8 | 9 | ## Environments you need before start 10 | 11 | | Name | Where to get? | 12 | | :------------------------ | :-------------------------------------------------------------------------------------------------------------- | 13 | | GITHUB_ACCESS_TOKEN | Generate a new personal access token in [GIthub Secure page](https://github.com/settings/tokens) | 14 | | AUTH_GITHUB_CLIENT_ID | Get in [Github app ID](https://github.com/organizations/devxp-tech/settings/applications/1927877) | 15 | | AUTH_GITHUB_CLIENT_SECRET | Open a tiket to Devxp to share this value | 16 | | SONARQUBE_TOKEN | Create a `Sonarqube` token using this [documentation](https://docs.sonarqube.org/latest/user-guide/user-token/) | 17 | 18 | All environments above `MUST` be exported in your bash context like below: 19 | 20 | ```sh 21 | # .bashrc or .zshrc 22 | export GITHUB_ACCESS_TOKEN='YOUR-TOKEN-HERE' 23 | export AUTH_GITHUB_CLIENT_ID='YOUR-TOKEN-HERE' 24 | export AUTH_GITHUB_CLIENT_SECRET='YOUR-TOKEN-HERE' 25 | export SONARQUBE_TOKEN='YOUR-TOKEN-HERE' 26 | ``` 27 | 28 | ## Setup your hosts 29 | 30 | You'll need to create an entry to your `/etc/hosts` to specify `backstage.local` like below: 31 | 32 | ```sh 33 | # /etc/hosts 34 | 35 | # ... 36 | 127.0.0.1 backstage.local 37 | #... 38 | 39 | ``` 40 | 41 | ## 🚀 Start project 42 | 43 | You'll need `Docker` and `docker-compose` installed before you continue! 44 | 45 | Once all you need is in your bash context, just run the commands below: 46 | 47 | ```sh 48 | docker-compose run --rm app yarn # to install node_modules 49 | docker-compose up -d app # to up the backstage application 50 | ``` 51 | 52 | Backstage in develop mode will be available in and it's using `GitHub SSO integration` 53 | 54 | ## 🆙 Backstage Update 55 | 56 | ```sh 57 | docker-compose run --rm app bash 58 | yarn backstage-cli versions:bump 59 | ``` 60 | 61 | ## 🚦 Work Flux 62 | 63 | ```mermaid 64 | graph TD; 65 | Dev-->Backstage; 66 | Backstage--create-->devxp-app; 67 | devxp-app-->golang; 68 | devxp-app-->python; 69 | devxp-app-->node; 70 | golang--new-app-->backstage-catalog; 71 | backstage-catalog--fetch-->github/devxp-tech/template-golang; 72 | backstage-catalog--fetch-->kubernetes-skelleton; 73 | backstage-catalog--push-->github/devxp-tech/new-app; 74 | kubernetes-skelleton--PullRequest-->ArgoCD; 75 | github/devxp-tech/new-app--workflow-->devxp-tech/.github/workflows; 76 | ArgoCD--pull-->helm-charts/devxp-app; 77 | ArgoCD--deploy-->Kubernetes; 78 | devxp-tech/.github/workflows--push/docker-image-->ghcr.github.com/devxp-tech; 79 | Kubernetes--pull/docker-image-->ghcr.github.com/devxp-tech; 80 | Kubernetes-->new-app; 81 | ``` 82 | 83 | ## 🧩 References 84 | 85 | - [ArgoCD](https://github.com/devxp-tech/gitops) 86 | - [helm-charts](https://github.com/devxp-tech/helm-charts) 87 | - [Backstage](https://github.com/devxp-tech/backstage) 88 | - [backstage-catalog:](https://github.com/devxp-tech/backstage-catalog) 89 | - [template-golang](https://github.com/devxp-tech/template-golang) 90 | - [github-workflows](https://github.com/devxp-tech/.github) 91 | 92 | 93 | ## ✨ Contributions 94 | 95 | We ❤️ contributions big or small. [See our guide](contributing.md) on how to get started. 96 | 97 | ### Thanks to all our contributors! 98 | 99 | 100 | 101 | 102 | 103 | Made with 💜 by DevXP-Tech. 104 | 105 | 106 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Backstage 2 | 3 | ## Add release pipeline 4 | 5 | ### Update Backstage 2 6 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /app/.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .yarn/cache 3 | .yarn/install-state.gz 4 | node_modules 5 | packages/*/src 6 | packages/*/node_modules 7 | plugins 8 | *.local.yaml 9 | -------------------------------------------------------------------------------- /app/.eslintignore: -------------------------------------------------------------------------------- 1 | playwright.config.ts 2 | -------------------------------------------------------------------------------- /app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | }; 4 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Coverage directory generated when running tests with coverage 13 | coverage 14 | 15 | # Dependencies 16 | node_modules/ 17 | 18 | # Yarn 3 files 19 | .pnp.* 20 | .yarn/* 21 | !.yarn/patches 22 | !.yarn/plugins 23 | !.yarn/releases 24 | !.yarn/sdks 25 | !.yarn/versions 26 | 27 | # Node version directives 28 | .nvmrc 29 | 30 | # dotenv environment variables file 31 | .env 32 | .env.test 33 | 34 | # Build output 35 | dist 36 | dist-types 37 | 38 | # Temporary change files created by Vim 39 | *.swp 40 | 41 | # MkDocs build output 42 | site 43 | 44 | # Local configuration files 45 | *.local.yaml 46 | 47 | # Sensitive credentials 48 | *-credentials.yaml 49 | 50 | # vscode database functionality support files 51 | *.session.sql 52 | 53 | # E2E test reports 54 | e2e-test-report/ 55 | -------------------------------------------------------------------------------- /app/.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | dist-types 3 | coverage 4 | .vscode 5 | -------------------------------------------------------------------------------- /app/.yarnrc: -------------------------------------------------------------------------------- 1 | network-timeout 500000 2 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # [Backstage](https://backstage.io) 2 | 3 | This is your newly scaffolded Backstage App, Good Luck! 4 | 5 | To start the app, run: 6 | 7 | ```sh 8 | yarn install 9 | yarn dev 10 | ``` 11 | -------------------------------------------------------------------------------- /app/app-config.production.yaml: -------------------------------------------------------------------------------- 1 | app: 2 | title: DevXP Technologies 3 | baseUrl: https://backstage.devxp-tech.io 4 | 5 | backend: 6 | # Note that the baseUrl should be the URL that the browser and other clients 7 | # should use when communicating with the backend, i.e. it needs to be 8 | # reachable not just from within the backend host, but from all of your 9 | # callers. When its value is "http://localhost:7007", it's strictly private 10 | # and can't be reached by others. 11 | baseUrl: https://backstage.devxp-tech.io 12 | listen: 13 | port: 7007 14 | host: 0.0.0.0 15 | 16 | csp: 17 | connect-src: ["'self'", "http:", "https:"] 18 | # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference 19 | # Default Helmet Content-Security-Policy values can be removed by setting the key to false 20 | 21 | cors: 22 | origin: https://backstage.devxp-tech.io 23 | #methods: [GET, POST, PUT, DELETE] 24 | #credentials: true 25 | # config options: https://node-postgres.com/api/client 26 | 27 | cache: 28 | store: memory 29 | # workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir 30 | 31 | integrations: 32 | github: 33 | - host: github.com 34 | token: ${GITHUB_TOKEN} 35 | aws: 36 | mainAccount: 37 | profile: development 38 | accounts: 39 | - accountId: ${AWS_ACCOUNT_ID} 40 | accessKeyId: ${AWS_ACCESS_KEY_ID} 41 | secretAccessKey: ${AWS_SECRET_ACCESS_KEY} 42 | profile: development 43 | 44 | kubernetes: 45 | serviceLocatorMethod: 46 | type: multiTenant 47 | clusterLocatorMethods: 48 | - type: config 49 | clusters: 50 | - url: ${K8S_URL} 51 | name: lgseksd1 52 | authProvider: serviceAccount 53 | skipTLSVerify: false 54 | skipMetricsLookup: true 55 | serviceAccountToken: ${SA_TOKEN} 56 | caData: ${CA_DATA} 57 | customResources: 58 | - group: "argoproj.io" 59 | apiVersion: "v1alpha1" 60 | plural: "rollouts" 61 | - group: "argoproj.io" 62 | apiVersion: "v1alpha1" 63 | plural: "applications" 64 | - group: "argoproj.io" 65 | apiVersion: "v1alpha1" 66 | plural: "appprojects" 67 | - group: "networking.istio.io" 68 | apiVersion: "v1beta1" 69 | plural: "virtualservices" 70 | 71 | # Reference documentation http://backstage.io/docs/features/techdocs/configuration 72 | # Note: After experimenting with basic setup, use CI/CD to generate docs 73 | # and an external cloud storage when deploying TechDocs for production use-case. 74 | # https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach 75 | 76 | techdocs: 77 | builder: "external" # Alternatives - 'external' 78 | # generator: 79 | # runIn: 'docker' 80 | publisher: 81 | type: "awsS3" 82 | awsS3: 83 | bucketName: ${TECHDOCS_BUCKET} 84 | accountId: ${AWS_ACCOUNT_ID} 85 | region: ${AWS_REGION} 86 | 87 | proxy: 88 | endpoints: 89 | "/argocd/api": 90 | target: https://argocd.devxp-tech.io/api/v1/ 91 | changeOrigin: true 92 | # only if your argocd api has self-signed cert 93 | secure: true 94 | headers: 95 | Cookie: 96 | $env: ARGOCD_AUTH_TOKEN 97 | 98 | "/grafana/api": 99 | # May be an internal DNS 100 | target: http://grafana.monitoring.svc/ 101 | headers: 102 | Authorization: Bearer ${GRAFANA_TOKEN} 103 | 104 | "/prometheus/api": 105 | # url to the api and path of your hosted prometheus instance 106 | target: http://prometheus-community-kube-prometheus.monitoring.svc.cluster.local:9090/api/v1/ 107 | 108 | auth: 109 | environment: production 110 | ### Providing an auth.session.secret will enable session support in the auth-backend 111 | # session: 112 | # secret: custom session secret 113 | providers: 114 | github: 115 | production: 116 | clientId: ${AUTH_GITHUB_CLIENT_ID} 117 | clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} 118 | -------------------------------------------------------------------------------- /app/app-config.yaml: -------------------------------------------------------------------------------- 1 | organization: 2 | name: DevXP Tech 3 | 4 | app: 5 | title: DevXP Tech Backstage - Development 6 | baseUrl: http://backstage.local:3000 7 | 8 | support: 9 | url: https://github.com/devxp-tech/backstage/issues # Used by common ErrorPage 10 | items: # Used by common SupportButton component 11 | - title: Issues 12 | icon: github 13 | links: 14 | - url: https://github.com/backstage/backstage/issues 15 | title: GitHub Issues 16 | - title: Slack Chatroom 17 | icon: chat 18 | links: 19 | - url: https://devxp-tech.slack.com/archives/C03L5M16CS2 20 | title: "#backstage" 21 | 22 | backend: 23 | # Used for enabling authentication, secret is shared by all backend plugins 24 | # See https://backstage.io/docs/auth/service-to-service-auth for 25 | # information on the format 26 | # auth: 27 | # keys: 28 | # - secret: ${BACKEND_SECRET} 29 | baseUrl: http://backstage.local:7007 30 | listen: 31 | port: 7007 32 | host: 0.0.0.0 33 | csp: 34 | connect-src: ["'self'", "http:", "https:"] 35 | img-src: ["'self'", "data:", "https://avatars.githubusercontent.com"] 36 | # Content-Security-Policy directives follow the Helmet format: https://helmetjs.github.io/#reference 37 | # Default Helmet Content-Security-Policy values can be removed by setting the key to false 38 | cors: 39 | origin: http://backstage.local:3000 40 | methods: [GET, HEAD, PATCH, POST, PUT, DELETE] 41 | credentials: true 42 | # This is for local development only, it is not recommended to use this in production 43 | # The production database configuration is stored in app-config.production.yaml 44 | database: 45 | client: pg 46 | connection: 47 | host: ${POSTGRES_HOST} 48 | port: ${POSTGRES_PORT} 49 | user: ${POSTGRES_USER} 50 | password: ${POSTGRES_PASSWORD} 51 | database: ${POSTGRES_DATABASE} 52 | ensureExists: true 53 | pluginDivisionMode: schema 54 | plugin: 55 | catalog: 56 | connection: 57 | database: ${POSTGRES_DATABASE} 58 | auth: 59 | connection: 60 | database: ${POSTGRES_DATABASE} 61 | app: 62 | connection: 63 | database: ${POSTGRES_DATABASE} 64 | scaffolder: 65 | connection: 66 | database: ${POSTGRES_DATABASE} 67 | cache: 68 | store: memory 69 | # workingDirectory: /tmp # Use this to configure a working directory for the scaffolder, defaults to the OS temp-dir 70 | 71 | integrations: 72 | github: 73 | - host: github.com 74 | # This is a Personal Access Token or PAT from GitHub. You can find out how to generate this token, and more information 75 | # about setting up the GitHub integration here: https://backstage.io/docs/getting-started/configuration#setting-up-a-github-integration 76 | token: ${GITHUB_TOKEN} 77 | aws: 78 | mainAccount: 79 | profile: development 80 | accounts: 81 | - accountId: ${AWS_ACCOUNT_ID} 82 | accessKeyId: ${AWS_ACCESS_KEY_ID} 83 | secretAccessKey: ${AWS_SECRET_ACCESS_KEY} 84 | profile: development 85 | 86 | # Reference documentation http://backstage.io/docs/features/techdocs/configuration 87 | # Note: After experimenting with basic setup, use CI/CD to generate docs 88 | # and an external cloud storage when deploying TechDocs for production use-case. 89 | # https://backstage.io/docs/features/techdocs/how-to-guides#how-to-migrate-from-techdocs-basic-to-recommended-deployment-approach 90 | techdocs: 91 | builder: "local" # Alternatives - 'external' 92 | generator: 93 | runIn: "docker" # Alternatives - 'local' 94 | publisher: 95 | type: "awsS3" 96 | awsS3: 97 | bucketName: ${TECHDOCS_BUCKET} 98 | region: ${AWS_REGION} 99 | credentials: 100 | accessKeyId: ${AWS_ACCESS_KEY_ID} 101 | secretAccessKey: ${AWS_SECRET_ACCESS_KEY} 102 | 103 | proxy: 104 | endpoints: 105 | "/argocd/api": 106 | target: https://argocd.devxp-tech.io/api/v1/ 107 | changeOrigin: true 108 | # only if your argocd api has self-signed cert 109 | secure: true 110 | headers: 111 | Cookie: 112 | $env: ARGOCD_AUTH_TOKEN 113 | 114 | "/grafana/api": 115 | # May be an internal DNS 116 | target: https://grafana.devxp-tech.io/ 117 | headers: 118 | Authorization: Bearer ${GRAFANA_TOKEN} 119 | 120 | "/prometheus/api": 121 | # url to the api and path of your hosted prometheus instance 122 | target: https://prometheus.devxp-tech.io/api/v1/ 123 | 124 | # '/snyk': 125 | # target: https://snyk.io/api/v1 126 | # headers: 127 | # User-Agent: tech-services/backstage-plugin/1.0 128 | # Authorization: 129 | # $env: SNYK_TOKEN 130 | 131 | # auth: 132 | # # see https://backstage.io/docs/auth/ to learn about auth providers 133 | # providers: {} 134 | 135 | auth: 136 | environment: development 137 | providers: 138 | github: 139 | development: 140 | clientId: ${AUTH_GITHUB_CLIENT_ID} 141 | clientSecret: ${AUTH_GITHUB_CLIENT_SECRET} 142 | 143 | dependabotAlertsConfiguration: 144 | severity: [high, medium] 145 | 146 | grafana: 147 | # Publicly accessible domain 148 | domain: https://grafana.devxp-tech.io 149 | 150 | kubecost: 151 | baseUrl: https://kubecost.devxp-tech.io 152 | sharedNamespaces: "monitoring,observability" 153 | queryframes: "week,yesterday,month,today,lastweek" 154 | unitprefix: "$" 155 | 156 | kubernetes: 157 | serviceLocatorMethod: 158 | type: multiTenant 159 | clusterLocatorMethods: 160 | - type: config 161 | clusters: 162 | - url: ${K8S_URL} 163 | name: development 164 | authProvider: serviceAccount 165 | skipTLSVerify: true 166 | skipMetricsLookup: true 167 | serviceAccountToken: ${K8S_TOKEN} 168 | customResources: 169 | # - group: "autoscaling" 170 | # apiVersion: "v1" 171 | # plural: "resourcequotas" 172 | - group: "argoproj.io" 173 | apiVersion: "v1alpha1" 174 | plural: "rollouts" 175 | - group: "argoproj.io" 176 | apiVersion: "v1alpha1" 177 | plural: "applications" 178 | - group: "argoproj.io" 179 | apiVersion: "v1alpha1" 180 | plural: "appprojects" 181 | - group: "networking.istio.io" 182 | apiVersion: "v1beta1" 183 | plural: "virtualservices" 184 | - group: "autoscaling" 185 | apiVersion: "v2" 186 | plural: "horizontalpodautoscalers" 187 | 188 | scaffolder: 189 | # see https://backstage.io/docs/features/software-templates/configuration for software template options 190 | defaultAuthor: 191 | name: ":robot: [backstage-bot]" 192 | email: backstage@devxp-tech.io 193 | # defaultCommitMessage: "🤖 U can't touch this" # Defaults to 'Initial commit' 194 | 195 | sonarqube: 196 | baseUrl: https://sonar.devxp-tech.io 197 | apiKey: ${SONARQUBE_TOKEN} 198 | 199 | catalog: 200 | orphanStrategy: delete 201 | providers: 202 | github: 203 | # the provider ID can be any camelCase string 204 | providerId: 205 | organization: "devxp-tech" # string 206 | catalogPath: "/catalog-info.yaml" # string 207 | filters: 208 | branch: "main" # string 209 | # repository: '.*' # Regex 210 | topic: 211 | include: ["backstage-include"] # optional array of strings 212 | exclude: ["backstage-exclude"] # optional array of strings 213 | schedule: # optional; same options as in TaskScheduleDefinition 214 | # supports cron, ISO duration, "human duration" as used in code 215 | frequency: { minutes: 30 } 216 | # supports ISO duration, "human duration" as used in code 217 | timeout: { minutes: 3 } 218 | import: 219 | entityFilename: catalog-info.yaml 220 | pullRequestBranchName: backstage-integration 221 | rules: 222 | - allow: 223 | - API 224 | - Component 225 | - Domain 226 | - Group 227 | - System 228 | - User 229 | - Template 230 | - Resource 231 | - Location 232 | 233 | locations: 234 | # - type: github-org 235 | # target: https://github.com/devxp-tech 236 | # rules: 237 | # - allow: [User, Group] 238 | 239 | - type: url 240 | target: https://github.com/devxp-tech/backstage-catalog/blob/main/devxp/all.yaml 241 | 242 | - type: url 243 | target: https://github.com/devxp-tech/backstage/blob/main/catalog-info.yaml 244 | -------------------------------------------------------------------------------- /app/backstage.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.21.1" 3 | } 4 | -------------------------------------------------------------------------------- /app/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: app 5 | description: An example of a Backstage application. 6 | # Example for optional annotations 7 | # annotations: 8 | # github.com/project-slug: backstage/backstage 9 | # backstage.io/techdocs-ref: dir:. 10 | spec: 11 | type: website 12 | owner: john@example.com 13 | lifecycle: experimental 14 | -------------------------------------------------------------------------------- /app/devspace_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set +e # Continue on errors 3 | 4 | export NODE_ENV=development 5 | if [ -f "yarn.lock" ]; then 6 | echo "Installing Yarn Dependencies" 7 | yarn install --frozen-lockfile --production --network-timeout 300000 8 | else 9 | if [ -f "package.json" ]; then 10 | echo "Installing NPM Dependencies" 11 | npm install 12 | fi 13 | fi 14 | 15 | COLOR_BLUE="\033[0;94m" 16 | COLOR_GREEN="\033[0;92m" 17 | COLOR_RESET="\033[0m" 18 | 19 | # Print useful output for user 20 | echo -e "${COLOR_BLUE} 21 | %########% 22 | %###########% ____ _____ 23 | %#########% | _ \ ___ __ __ / ___/ ____ ____ ____ ___ 24 | %#########% | | | | / _ \\\\\ \ / / \___ \ | _ \ / _ | / __// _ \\ 25 | %#############% | |_| |( __/ \ V / ____) )| |_) )( (_| |( (__( __/ 26 | %#############% |____/ \___| \_/ \____/ | __/ \__,_| \___\\\\\___| 27 | %###############% |_| 28 | %###########%${COLOR_RESET} 29 | 30 | 31 | Welcome to your development container! 32 | 33 | This is how you can work with it: 34 | - Files will be synchronized between your local machine and this container 35 | - Some ports will be forwarded, so you can access this container via localhost 36 | - Run \`${COLOR_GREEN}npm start${COLOR_RESET}\` to start the application 37 | " 38 | 39 | # Set terminal prompt 40 | export PS1="\[${COLOR_BLUE}\]devspace\[${COLOR_RESET}\] ./\W \[${COLOR_BLUE}\]\\$\[${COLOR_RESET}\] " 41 | if [ -z "$BASH" ]; then export PS1="$ "; fi 42 | 43 | # Include project's bin/ folder in PATH 44 | export PATH="./bin:$PATH" 45 | 46 | # Open shell 47 | bash --norc 48 | -------------------------------------------------------------------------------- /app/examples/entities.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-system 3 | apiVersion: backstage.io/v1alpha1 4 | kind: System 5 | metadata: 6 | name: examples 7 | spec: 8 | owner: guests 9 | --- 10 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component 11 | apiVersion: backstage.io/v1alpha1 12 | kind: Component 13 | metadata: 14 | name: example-website 15 | spec: 16 | type: website 17 | lifecycle: experimental 18 | owner: guests 19 | system: examples 20 | providesApis: [example-grpc-api] 21 | --- 22 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-api 23 | apiVersion: backstage.io/v1alpha1 24 | kind: API 25 | metadata: 26 | name: example-grpc-api 27 | spec: 28 | type: grpc 29 | lifecycle: experimental 30 | owner: guests 31 | system: examples 32 | definition: | 33 | syntax = "proto3"; 34 | 35 | service Exampler { 36 | rpc Example (ExampleMessage) returns (ExampleMessage) {}; 37 | } 38 | 39 | message ExampleMessage { 40 | string example = 1; 41 | }; 42 | -------------------------------------------------------------------------------- /app/examples/org.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user 3 | apiVersion: backstage.io/v1alpha1 4 | kind: User 5 | metadata: 6 | name: guest 7 | spec: 8 | memberOf: [guests] 9 | --- 10 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group 11 | apiVersion: backstage.io/v1alpha1 12 | kind: Group 13 | metadata: 14 | name: guests 15 | spec: 16 | type: team 17 | children: [] 18 | -------------------------------------------------------------------------------- /app/examples/template/content/catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: ${{ values.name | dump }} 5 | spec: 6 | type: service 7 | owner: user:guest 8 | lifecycle: experimental 9 | -------------------------------------------------------------------------------- /app/examples/template/content/index.js: -------------------------------------------------------------------------------- 1 | console.log('Hello from ${{ values.name }}!'); 2 | -------------------------------------------------------------------------------- /app/examples/template/content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${{ values.name }}", 3 | "private": true, 4 | "dependencies": {} 5 | } 6 | -------------------------------------------------------------------------------- /app/examples/template/template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: scaffolder.backstage.io/v1beta3 2 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template 3 | kind: Template 4 | metadata: 5 | name: example-nodejs-template 6 | title: Example Node.js Template 7 | description: An example template for the scaffolder that creates a simple Node.js service 8 | spec: 9 | owner: user:guest 10 | type: service 11 | 12 | # These parameters are used to generate the input form in the frontend, and are 13 | # used to gather input data for the execution of the template. 14 | parameters: 15 | - title: Fill in some steps 16 | required: 17 | - name 18 | properties: 19 | name: 20 | title: Name 21 | type: string 22 | description: Unique name of the component 23 | ui:autofocus: true 24 | ui:options: 25 | rows: 5 26 | - title: Choose a location 27 | required: 28 | - repoUrl 29 | properties: 30 | repoUrl: 31 | title: Repository Location 32 | type: string 33 | ui:field: RepoUrlPicker 34 | ui:options: 35 | allowedHosts: 36 | - github.com 37 | 38 | # These steps are executed in the scaffolder backend, using data that we gathered 39 | # via the parameters above. 40 | steps: 41 | # Each step executes an action, in this case one templates files into the working directory. 42 | - id: fetch-base 43 | name: Fetch Base 44 | action: fetch:template 45 | input: 46 | url: ./content 47 | values: 48 | name: ${{ parameters.name }} 49 | 50 | # This step publishes the contents of the working directory to GitHub. 51 | - id: publish 52 | name: Publish 53 | action: publish:github 54 | input: 55 | allowedHosts: ['github.com'] 56 | description: This is ${{ parameters.name }} 57 | repoUrl: ${{ parameters.repoUrl }} 58 | 59 | # The final step is to register our new component in the catalog. 60 | - id: register 61 | name: Register 62 | action: catalog:register 63 | input: 64 | repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }} 65 | catalogInfoPath: '/catalog-info.yaml' 66 | 67 | # Outputs are displayed to the user after a successful execution of the template. 68 | output: 69 | links: 70 | - title: Repository 71 | url: ${{ steps['publish'].output.remoteUrl }} 72 | - title: Open in catalog 73 | icon: catalog 74 | entityRef: ${{ steps['register'].output.entityRef }} 75 | -------------------------------------------------------------------------------- /app/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*", "plugins/*"], 3 | "npmClient": "yarn", 4 | "version": "0.1.0", 5 | "$schema": "node_modules/lerna/schemas/lerna-schema.json" 6 | } 7 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "version": "1.0.0", 4 | "private": true, 5 | "engines": { 6 | "node": "18 || 20" 7 | }, 8 | "scripts": { 9 | "dev": "concurrently \"yarn start\" \"yarn start-backend\"", 10 | "start": "yarn workspace app start", 11 | "start-backend": "yarn workspace backend start", 12 | "build:backend": "yarn workspace backend build", 13 | "build:all": "backstage-cli repo build --all", 14 | "build-image": "yarn workspace backend build-image", 15 | "tsc": "tsc", 16 | "tsc:full": "tsc --skipLibCheck false --incremental false", 17 | "clean": "backstage-cli repo clean", 18 | "test": "backstage-cli repo test", 19 | "test:all": "backstage-cli repo test --coverage", 20 | "test:e2e": "playwright test", 21 | "fix": "backstage-cli repo fix", 22 | "lint": "backstage-cli repo lint --since origin/master", 23 | "lint:all": "backstage-cli repo lint", 24 | "prettier:check": "prettier --check .", 25 | "new": "backstage-cli new --scope internal" 26 | }, 27 | "workspaces": { 28 | "packages": [ 29 | "packages/*", 30 | "plugins/*" 31 | ] 32 | }, 33 | "devDependencies": { 34 | "@backstage/cli": "^0.25.0", 35 | "@backstage/e2e-test-utils": "^0.1.0", 36 | "@playwright/test": "^1.32.3", 37 | "@spotify/prettier-config": "^12.0.0", 38 | "concurrently": "^8.0.0", 39 | "lerna": "^7.3.0", 40 | "node-gyp": "^9.0.0", 41 | "prettier": "^2.3.2", 42 | "typescript": "~5.2.0" 43 | }, 44 | "resolutions": { 45 | "@types/react": "^17", 46 | "@types/react-dom": "^17" 47 | }, 48 | "prettier": "@spotify/prettier-config", 49 | "lint-staged": { 50 | "*.{js,jsx,ts,tsx,mjs,cjs}": [ 51 | "eslint --fix", 52 | "prettier --write" 53 | ], 54 | "*.{json,md}": [ 55 | "prettier --write" 56 | ] 57 | }, 58 | "dependencies": { 59 | "@types/react": "^17" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/packages/README.md: -------------------------------------------------------------------------------- 1 | # The Packages Folder 2 | 3 | This is where your own applications and centrally managed libraries live, each 4 | in a separate folder of its own. 5 | 6 | From the start there's an `app` folder (for the frontend) and a `backend` folder 7 | (for the Node backend), but you can also add more modules in here that house 8 | your core additions and adaptations, such as themes, common React component 9 | libraries, utilities, and similar. 10 | -------------------------------------------------------------------------------- /app/packages/app/.eslintignore: -------------------------------------------------------------------------------- 1 | public 2 | -------------------------------------------------------------------------------- /app/packages/app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); 2 | -------------------------------------------------------------------------------- /app/packages/app/e2e-tests/app.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Backstage Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { test, expect } from '@playwright/test'; 18 | 19 | test('App should render the welcome page', async ({ page }) => { 20 | await page.goto('/'); 21 | 22 | await expect(page.getByText('My Company Catalog')).toBeVisible(); 23 | }); 24 | -------------------------------------------------------------------------------- /app/packages/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.0", 4 | "private": true, 5 | "bundled": true, 6 | "backstage": { 7 | "role": "frontend" 8 | }, 9 | "scripts": { 10 | "start": "backstage-cli package start", 11 | "build": "backstage-cli package build", 12 | "clean": "backstage-cli package clean", 13 | "test": "backstage-cli package test", 14 | "lint": "backstage-cli package lint" 15 | }, 16 | "dependencies": { 17 | "@backstage/app-defaults": "^1.4.6", 18 | "@backstage/catalog-model": "^1.4.3", 19 | "@backstage/cli": "^0.25.0", 20 | "@backstage/core-app-api": "^1.11.2", 21 | "@backstage/core-components": "^0.13.9", 22 | "@backstage/core-plugin-api": "^1.8.1", 23 | "@backstage/integration-aws-node": "^0.1.8", 24 | "@backstage/integration-react": "^1.1.22", 25 | "@backstage/plugin-api-docs": "^0.10.2", 26 | "@backstage/plugin-catalog": "^1.16.0", 27 | "@backstage/plugin-catalog-common": "^1.0.19", 28 | "@backstage/plugin-catalog-graph": "^0.3.2", 29 | "@backstage/plugin-catalog-import": "^0.10.4", 30 | "@backstage/plugin-catalog-react": "^1.9.2", 31 | "@backstage/plugin-github-actions": "^0.6.9", 32 | "@backstage/plugin-home": "^0.6.0", 33 | "@backstage/plugin-kubernetes": "^0.11.3", 34 | "@backstage/plugin-org": "^0.6.18", 35 | "@backstage/plugin-permission-react": "^0.4.18", 36 | "@backstage/plugin-scaffolder": "^1.17.0", 37 | "@backstage/plugin-search": "^1.4.4", 38 | "@backstage/plugin-search-react": "^1.7.4", 39 | "@backstage/plugin-sonarqube": "^0.7.10", 40 | "@backstage/plugin-tech-radar": "^0.6.11", 41 | "@backstage/plugin-techdocs": "^1.9.2", 42 | "@backstage/plugin-techdocs-module-addons-contrib": "^1.1.3", 43 | "@backstage/plugin-techdocs-react": "^1.1.14", 44 | "@backstage/plugin-todo": "^0.2.32", 45 | "@backstage/plugin-user-settings": "^0.7.14", 46 | "@backstage/theme": "^0.5.0", 47 | "@k-phoen/backstage-plugin-grafana": "^0.1.22", 48 | "@material-ui/core": "^4.12.2", 49 | "@material-ui/icons": "^4.9.1", 50 | "@roadiehq/backstage-plugin-argo-cd": "^2.5.0", 51 | "@roadiehq/backstage-plugin-github-insights": "^2.3.23", 52 | "@roadiehq/backstage-plugin-github-pull-requests": "^2.5.20", 53 | "@roadiehq/backstage-plugin-prometheus": "^2.8.2", 54 | "@roadiehq/backstage-plugin-security-insights": "^2.3.11", 55 | "@suxess-it/backstage-plugin-kubecost": "^0.2.6", 56 | "history": "^5.0.0", 57 | "react": "^17.0.2", 58 | "react-dom": "^17.0.2", 59 | "react-router": "^6.3.0", 60 | "react-router-dom": "^6.3.0", 61 | "react-use": "^17.2.4" 62 | }, 63 | "devDependencies": { 64 | "@backstage/test-utils": "^1.4.6", 65 | "@playwright/test": "^1.32.3", 66 | "@testing-library/dom": "^8.0.0", 67 | "@testing-library/jest-dom": "^5.10.1", 68 | "@testing-library/react": "^12.1.3", 69 | "@testing-library/user-event": "^14.0.0", 70 | "@types/react-dom": "*", 71 | "cross-env": "^7.0.0" 72 | }, 73 | "browserslist": { 74 | "production": [ 75 | ">0.2%", 76 | "not dead", 77 | "not op_mini all" 78 | ], 79 | "development": [ 80 | "last 1 chrome version", 81 | "last 1 firefox version", 82 | "last 1 safari version" 83 | ] 84 | }, 85 | "files": [ 86 | "dist" 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /app/packages/app/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devxp-tech/backstage/ff1ec7f42090c078cdd9b5d854db9d212e42963a/app/packages/app/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /app/packages/app/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devxp-tech/backstage/ff1ec7f42090c078cdd9b5d854db9d212e42963a/app/packages/app/public/apple-touch-icon.png -------------------------------------------------------------------------------- /app/packages/app/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devxp-tech/backstage/ff1ec7f42090c078cdd9b5d854db9d212e42963a/app/packages/app/public/favicon-16x16.png -------------------------------------------------------------------------------- /app/packages/app/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devxp-tech/backstage/ff1ec7f42090c078cdd9b5d854db9d212e42963a/app/packages/app/public/favicon-32x32.png -------------------------------------------------------------------------------- /app/packages/app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devxp-tech/backstage/ff1ec7f42090c078cdd9b5d854db9d212e42963a/app/packages/app/public/favicon.ico -------------------------------------------------------------------------------- /app/packages/app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 15 | 20 | 21 | 22 | 27 | 33 | 39 | 44 | <%= config.getString('app.title') %> 45 | 46 | 47 | 48 |
49 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/packages/app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Backstage", 3 | "name": "Backstage", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "48x48", 8 | "type": "image/png" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /app/packages/app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /app/packages/app/public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | Created by potrace 1.11, written by Peter Selinger 2001-2013 -------------------------------------------------------------------------------- /app/packages/app/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { renderWithEffects } from '@backstage/test-utils'; 3 | import App from './App'; 4 | 5 | describe('App', () => { 6 | it('should render', async () => { 7 | process.env = { 8 | NODE_ENV: 'test', 9 | APP_CONFIG: [ 10 | { 11 | data: { 12 | app: { title: 'Test' }, 13 | backend: { baseUrl: 'http://localhost:7007' }, 14 | techdocs: { 15 | storageUrl: 'http://localhost:7007/api/techdocs/static/docs', 16 | }, 17 | }, 18 | context: 'test', 19 | }, 20 | ] as any, 21 | }; 22 | 23 | const rendered = await renderWithEffects(); 24 | expect(rendered.baseElement).toBeInTheDocument(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /app/packages/app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Navigate, Route } from 'react-router-dom'; 3 | import { apiDocsPlugin, ApiExplorerPage } from '@backstage/plugin-api-docs'; 4 | import { 5 | CatalogEntityPage, 6 | CatalogIndexPage, 7 | catalogPlugin, 8 | } from '@backstage/plugin-catalog'; 9 | import { 10 | CatalogImportPage, 11 | catalogImportPlugin, 12 | } from '@backstage/plugin-catalog-import'; 13 | import { ScaffolderPage, scaffolderPlugin } from '@backstage/plugin-scaffolder'; 14 | import { orgPlugin } from '@backstage/plugin-org'; 15 | import { SearchPage } from '@backstage/plugin-search'; 16 | import { TechRadarPage } from '@backstage/plugin-tech-radar'; 17 | import { 18 | TechDocsIndexPage, 19 | techdocsPlugin, 20 | TechDocsReaderPage, 21 | } from '@backstage/plugin-techdocs'; 22 | import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; 23 | import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; 24 | import { UserSettingsPage } from '@backstage/plugin-user-settings'; 25 | import { apis } from './apis'; 26 | import { entityPage } from './components/catalog/EntityPage'; 27 | import { searchPage } from './components/search/SearchPage'; 28 | import { Root } from './components/Root'; 29 | 30 | import { AlertDisplay, OAuthRequestDialog } from '@backstage/core-components'; 31 | import { createApp } from '@backstage/app-defaults'; 32 | import { AppRouter, FlatRoutes } from '@backstage/core-app-api'; 33 | import { CatalogGraphPage } from '@backstage/plugin-catalog-graph'; 34 | import { RequirePermission } from '@backstage/plugin-permission-react'; 35 | import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha'; 36 | 37 | import { githubAuthApiRef } from '@backstage/core-plugin-api'; 38 | import { SignInPage } from '@backstage/core-components'; 39 | 40 | 41 | // import { EntitySnykContent } from 'backstage-plugin-snyk'; 42 | 43 | const app = createApp({ 44 | apis, 45 | 46 | components: { 47 | SignInPage: props => ( 48 | 58 | ), 59 | }, 60 | 61 | bindRoutes({ bind }) { 62 | bind(catalogPlugin.externalRoutes, { 63 | createComponent: scaffolderPlugin.routes.root, 64 | viewTechDoc: techdocsPlugin.routes.docRoot, 65 | createFromTemplate: scaffolderPlugin.routes.selectedTemplate, 66 | }); 67 | bind(apiDocsPlugin.externalRoutes, { 68 | registerApi: catalogImportPlugin.routes.importPage, 69 | }); 70 | bind(scaffolderPlugin.externalRoutes, { 71 | registerComponent: catalogImportPlugin.routes.importPage, 72 | viewTechDoc: techdocsPlugin.routes.docRoot, 73 | }); 74 | bind(orgPlugin.externalRoutes, { 75 | catalogIndex: catalogPlugin.routes.catalogIndex, 76 | }); 77 | }, 78 | }); 79 | 80 | const routes = ( 81 | 82 | } /> 83 | } /> 84 | } 87 | > 88 | {entityPage} 89 | 90 | } /> 91 | } 94 | > 95 | 96 | 97 | 98 | 99 | } /> 100 | } /> 101 | } 104 | /> 105 | 109 | 110 | 111 | } 112 | /> 113 | }> 114 | {searchPage} 115 | 116 | } /> 117 | } /> 118 | 119 | ); 120 | 121 | export default app.createRoot( 122 | <> 123 | 124 | 125 | 126 | {routes} 127 | 128 | , 129 | ); 130 | -------------------------------------------------------------------------------- /app/packages/app/src/apis.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ScmIntegrationsApi, 3 | scmIntegrationsApiRef, 4 | ScmAuth, 5 | } from '@backstage/integration-react'; 6 | import { 7 | AnyApiFactory, 8 | configApiRef, 9 | createApiFactory, 10 | } from '@backstage/core-plugin-api'; 11 | 12 | export const apis: AnyApiFactory[] = [ 13 | createApiFactory({ 14 | api: scmIntegrationsApiRef, 15 | deps: { configApi: configApiRef }, 16 | factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), 17 | }), 18 | ScmAuth.createDefaultApiFactory(), 19 | ]; 20 | -------------------------------------------------------------------------------- /app/packages/app/src/components/Root/LogoFull.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { makeStyles } from '@material-ui/core'; 3 | 4 | const useStyles = makeStyles({ 5 | svg: { 6 | width: 'auto', 7 | height: 30, 8 | }, 9 | path: { 10 | fill: '#7df3e1', 11 | }, 12 | }); 13 | const LogoFull = () => { 14 | const classes = useStyles(); 15 | 16 | return ( 17 | 22 | 26 | 27 | ); 28 | }; 29 | 30 | export default LogoFull; 31 | -------------------------------------------------------------------------------- /app/packages/app/src/components/Root/LogoIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { makeStyles } from '@material-ui/core'; 3 | 4 | const useStyles = makeStyles({ 5 | svg: { 6 | width: 'auto', 7 | height: 28, 8 | }, 9 | path: { 10 | fill: '#7df3e1', 11 | }, 12 | }); 13 | 14 | const LogoIcon = () => { 15 | const classes = useStyles(); 16 | 17 | return ( 18 | 23 | 27 | 28 | ); 29 | }; 30 | 31 | export default LogoIcon; 32 | -------------------------------------------------------------------------------- /app/packages/app/src/components/Root/Root.tsx: -------------------------------------------------------------------------------- 1 | import React, { PropsWithChildren } from 'react'; 2 | import { makeStyles } from '@material-ui/core'; 3 | import HomeIcon from '@material-ui/icons/Home'; 4 | import ExtensionIcon from '@material-ui/icons/Extension'; 5 | import MapIcon from '@material-ui/icons/MyLocation'; 6 | import LibraryBooks from '@material-ui/icons/LibraryBooks'; 7 | import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; 8 | import LogoFull from './LogoFull'; 9 | import LogoIcon from './LogoIcon'; 10 | import { 11 | Settings as SidebarSettings, 12 | UserSettingsSignInAvatar, 13 | } from '@backstage/plugin-user-settings'; 14 | import { SidebarSearchModal } from '@backstage/plugin-search'; 15 | import { 16 | Sidebar, 17 | sidebarConfig, 18 | SidebarDivider, 19 | SidebarGroup, 20 | SidebarItem, 21 | SidebarPage, 22 | SidebarScrollWrapper, 23 | SidebarSpace, 24 | useSidebarOpenState, 25 | Link, 26 | } from '@backstage/core-components'; 27 | import MenuIcon from '@material-ui/icons/Menu'; 28 | import SearchIcon from '@material-ui/icons/Search'; 29 | 30 | const useSidebarLogoStyles = makeStyles({ 31 | root: { 32 | width: sidebarConfig.drawerWidthClosed, 33 | height: 3 * sidebarConfig.logoHeight, 34 | display: 'flex', 35 | flexFlow: 'row nowrap', 36 | alignItems: 'center', 37 | marginBottom: -14, 38 | }, 39 | link: { 40 | width: sidebarConfig.drawerWidthClosed, 41 | marginLeft: 24, 42 | }, 43 | }); 44 | 45 | const SidebarLogo = () => { 46 | const classes = useSidebarLogoStyles(); 47 | const { isOpen } = useSidebarOpenState(); 48 | 49 | return ( 50 |
51 | 52 | {isOpen ? : } 53 | 54 |
55 | ); 56 | }; 57 | 58 | export const Root = ({ children }: PropsWithChildren<{}>) => ( 59 | 60 | 61 | 62 | } to="/search"> 63 | 64 | 65 | 66 | }> 67 | {/* Global nav, not org-specific */} 68 | 69 | 70 | 71 | 72 | {/* End global nav */} 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | } 83 | to="/settings" 84 | > 85 | 86 | 87 | 88 | {children} 89 | 90 | ); 91 | -------------------------------------------------------------------------------- /app/packages/app/src/components/Root/index.ts: -------------------------------------------------------------------------------- 1 | export { Root } from './Root'; 2 | -------------------------------------------------------------------------------- /app/packages/app/src/components/catalog/EntityPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Grid } from '@material-ui/core'; 3 | import { 4 | EntityApiDefinitionCard, 5 | EntityConsumedApisCard, 6 | EntityConsumingComponentsCard, 7 | EntityHasApisCard, 8 | EntityProvidedApisCard, 9 | EntityProvidingComponentsCard, 10 | } from '@backstage/plugin-api-docs'; 11 | import { 12 | EntityAboutCard, 13 | EntityDependsOnComponentsCard, 14 | EntityDependsOnResourcesCard, 15 | EntityHasComponentsCard, 16 | EntityHasResourcesCard, 17 | EntityHasSubcomponentsCard, 18 | EntityHasSystemsCard, 19 | EntityLayout, 20 | EntityLinksCard, 21 | EntitySwitch, 22 | EntityOrphanWarning, 23 | EntityProcessingErrorsPanel, 24 | isComponentType, 25 | isKind, 26 | hasCatalogProcessingErrors, 27 | isOrphan, 28 | hasRelationWarnings, 29 | EntityRelationWarning, 30 | } from '@backstage/plugin-catalog'; 31 | import { 32 | isGithubActionsAvailable, 33 | EntityGithubActionsContent, 34 | } from '@backstage/plugin-github-actions'; 35 | import { 36 | EntityUserProfileCard, 37 | EntityGroupProfileCard, 38 | EntityMembersListCard, 39 | EntityOwnershipCard, 40 | } from '@backstage/plugin-org'; 41 | import { EntityTechdocsContent } from '@backstage/plugin-techdocs'; 42 | import { EmptyState } from '@backstage/core-components'; 43 | import { 44 | Direction, 45 | EntityCatalogGraphCard, 46 | } from '@backstage/plugin-catalog-graph'; 47 | import { 48 | RELATION_API_CONSUMED_BY, 49 | RELATION_API_PROVIDED_BY, 50 | RELATION_CONSUMES_API, 51 | RELATION_DEPENDENCY_OF, 52 | RELATION_DEPENDS_ON, 53 | RELATION_HAS_PART, 54 | RELATION_PART_OF, 55 | RELATION_PROVIDES_API, 56 | } from '@backstage/catalog-model'; 57 | 58 | import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; 59 | import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; 60 | 61 | 62 | 63 | import { EntityGithubInsightsContent } from '@roadiehq/backstage-plugin-github-insights'; 64 | import { EntityGithubPullRequestsContent } from '@roadiehq/backstage-plugin-github-pull-requests'; 65 | import { 66 | DependabotAlertsWidget, 67 | EntityGithubDependabotContent, 68 | EntitySecurityInsightsContent, 69 | isSecurityInsightsAvailable, 70 | } from '@roadiehq/backstage-plugin-security-insights'; 71 | import { EntityKubernetesContent } from '@backstage/plugin-kubernetes'; 72 | import { EntitySonarQubeCard } from '@backstage/plugin-sonarqube'; 73 | import { EntityTodoContent } from '@backstage/plugin-todo'; 74 | // import { SnykOverview, EntitySnykContent, isSnykAvailable } from 'backstage-plugin-snyk'; 75 | 76 | import { 77 | BackstagePluginKubecostPage, 78 | isKubecostAvailable 79 | } from '@suxess-it/backstage-plugin-kubecost'; 80 | 81 | import { 82 | EntityArgoCDOverviewCard, 83 | isArgocdAvailable 84 | } from '@roadiehq/backstage-plugin-argo-cd'; 85 | 86 | import { 87 | EntityGrafanaDashboardsCard, 88 | } from '@k-phoen/backstage-plugin-grafana'; 89 | 90 | import { 91 | EntityGrafanaAlertsCard, 92 | } from '@k-phoen/backstage-plugin-grafana'; 93 | 94 | import { 95 | // EntityPrometheusAlertCard, 96 | EntityPrometheusContent, 97 | } from '@roadiehq/backstage-plugin-prometheus'; 98 | 99 | 100 | const techdocsContent = ( 101 | 102 | 103 | 104 | 105 | 106 | ); 107 | 108 | const cicdContent = ( 109 | // This is an example of how you can implement your company's logic in entity page. 110 | // You can for example enforce that all components of type 'service' should use GitHubActions 111 | 112 | 113 | 114 | 115 | 116 | 117 | 127 | Read more 128 | 129 | } 130 | /> 131 | 132 | 133 | ); 134 | 135 | const entityWarningContent = ( 136 | <> 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | ); 162 | 163 | const overviewContent = ( 164 | 165 | {entityWarningContent} 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | Boolean(isArgocdAvailable(e))}> 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | {/* 203 | 204 | 205 | 206 | 207 | 208 | */} 209 | 210 | 211 | {/* Grafana alert card start */} 212 | 213 | {/* Grafana alert card end */} 214 | 215 | 216 | 217 | {/* Grafana alert card start */} 218 | 219 | {/* Grafana alert card end */} 220 | 221 | 222 | 223 | ); 224 | 225 | const serviceEntityPage = ( 226 | 227 | 228 | {overviewContent} 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | {cicdContent} 245 | 246 | 247 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | {/* 258 | 259 | */} 260 | 261 | 264 | 265 | 266 | 267 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | {techdocsContent} 301 | 302 | 303 | ); 304 | 305 | const websiteEntityPage = ( 306 | 307 | 308 | {overviewContent} 309 | 310 | 311 | 312 | {cicdContent} 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | {techdocsContent} 328 | 329 | 330 | ); 331 | 332 | /** 333 | * NOTE: This page is designed to work on small screens such as mobile devices. 334 | * This is based on Material UI Grid. If breakpoints are used, each grid item must set the `xs` prop to a column size or to `true`, 335 | * since this does not default. If no breakpoints are used, the items will equitably share the available space. 336 | * https://material-ui.com/components/grid/#basic-grid. 337 | */ 338 | 339 | const defaultEntityPage = ( 340 | 341 | 342 | {overviewContent} 343 | 344 | 345 | 346 | {techdocsContent} 347 | 348 | 349 | ); 350 | 351 | const componentPage = ( 352 | 353 | 354 | {serviceEntityPage} 355 | 356 | 357 | 358 | {websiteEntityPage} 359 | 360 | 361 | {defaultEntityPage} 362 | 363 | ); 364 | 365 | const apiPage = ( 366 | 367 | 368 | 369 | {entityWarningContent} 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | ); 399 | 400 | const userPage = ( 401 | 402 | 403 | 404 | {entityWarningContent} 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | ); 415 | 416 | const groupPage = ( 417 | 418 | 419 | 420 | {entityWarningContent} 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | ); 437 | 438 | const systemPage = ( 439 | 440 | 441 | 442 | {entityWarningContent} 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 481 | 482 | 483 | ); 484 | 485 | const domainPage = ( 486 | 487 | 488 | 489 | {entityWarningContent} 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | ); 503 | 504 | export const entityPage = ( 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | {defaultEntityPage} 514 | 515 | ); 516 | -------------------------------------------------------------------------------- /app/packages/app/src/components/search/SearchPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { makeStyles, Theme, Grid, Paper } from '@material-ui/core'; 3 | 4 | import { CatalogSearchResultListItem } from '@backstage/plugin-catalog'; 5 | import { 6 | catalogApiRef, 7 | CATALOG_FILTER_EXISTS, 8 | } from '@backstage/plugin-catalog-react'; 9 | import { TechDocsSearchResultListItem } from '@backstage/plugin-techdocs'; 10 | 11 | import { SearchType } from '@backstage/plugin-search'; 12 | import { 13 | SearchBar, 14 | SearchFilter, 15 | SearchResult, 16 | SearchPagination, 17 | useSearch, 18 | } from '@backstage/plugin-search-react'; 19 | import { 20 | CatalogIcon, 21 | Content, 22 | DocsIcon, 23 | Header, 24 | Page, 25 | } from '@backstage/core-components'; 26 | import { useApi } from '@backstage/core-plugin-api'; 27 | 28 | const useStyles = makeStyles((theme: Theme) => ({ 29 | bar: { 30 | padding: theme.spacing(1, 0), 31 | }, 32 | filters: { 33 | padding: theme.spacing(2), 34 | marginTop: theme.spacing(2), 35 | }, 36 | filter: { 37 | '& + &': { 38 | marginTop: theme.spacing(2.5), 39 | }, 40 | }, 41 | })); 42 | 43 | const SearchPage = () => { 44 | const classes = useStyles(); 45 | const { types } = useSearch(); 46 | const catalogApi = useApi(catalogApiRef); 47 | 48 | return ( 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | , 67 | }, 68 | { 69 | value: 'techdocs', 70 | name: 'Documentation', 71 | icon: , 72 | }, 73 | ]} 74 | /> 75 | 76 | {types.includes('techdocs') && ( 77 | { 82 | // Return a list of entities which are documented. 83 | const { items } = await catalogApi.getEntities({ 84 | fields: ['metadata.name'], 85 | filter: { 86 | 'metadata.annotations.backstage.io/techdocs-ref': 87 | CATALOG_FILTER_EXISTS, 88 | }, 89 | }); 90 | 91 | const names = items.map(entity => entity.metadata.name); 92 | names.sort(); 93 | return names; 94 | }} 95 | /> 96 | )} 97 | 103 | 109 | 110 | 111 | 112 | 113 | 114 | } /> 115 | } /> 116 | 117 | 118 | 119 | 120 | 121 | ); 122 | }; 123 | 124 | export const searchPage = ; 125 | -------------------------------------------------------------------------------- /app/packages/app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import '@backstage/cli/asset-types'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import App from './App'; 5 | 6 | ReactDOM.render(, document.getElementById('root')); 7 | -------------------------------------------------------------------------------- /app/packages/app/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /app/packages/backend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); 2 | -------------------------------------------------------------------------------- /app/packages/backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # This dockerfile builds an image for the backend package. 2 | # It should be executed with the root of the repo as docker context. 3 | # 4 | # Before building this image, be sure to have run the following commands in the repo root: 5 | # 6 | # yarn install 7 | # yarn tsc 8 | # yarn build:backend 9 | # 10 | # Once the commands have been run, you can build the image using `yarn build-image` 11 | 12 | FROM node:18-bookworm-slim 13 | 14 | # Install isolate-vm dependencies, these are needed by the @backstage/plugin-scaffolder-backend. 15 | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 16 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 17 | apt-get update && \ 18 | apt-get install -y --no-install-recommends python3 g++ build-essential && \ 19 | yarn config set python /usr/bin/python3 20 | 21 | # Install sqlite3 dependencies. You can skip this if you don't use sqlite3 in the image, 22 | # in which case you should also move better-sqlite3 to "devDependencies" in package.json. 23 | RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ 24 | --mount=type=cache,target=/var/lib/apt,sharing=locked \ 25 | apt-get update && \ 26 | apt-get install -y --no-install-recommends libsqlite3-dev 27 | 28 | # From here on we use the least-privileged `node` user to run the backend. 29 | USER node 30 | 31 | # This should create the app dir as `node`. 32 | # If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`. 33 | # If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`. 34 | WORKDIR /app 35 | 36 | # This switches many Node.js dependencies to production mode. 37 | ENV NODE_ENV production 38 | 39 | # Copy repo skeleton first, to avoid unnecessary docker cache invalidation. 40 | # The skeleton contains the package.json of each package in the monorepo, 41 | # and along with yarn.lock and the root package.json, that's enough to run yarn install. 42 | COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./ 43 | RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz 44 | 45 | RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ 46 | yarn install --frozen-lockfile --production --network-timeout 300000 47 | 48 | # Then copy the rest of the backend bundle, along with any other files we might want. 49 | COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./ 50 | RUN tar xzf bundle.tar.gz && rm bundle.tar.gz 51 | 52 | CMD ["node", "packages/backend", "--config", "app-config.yaml", "--config", "app-config.production.yaml"] 53 | -------------------------------------------------------------------------------- /app/packages/backend/README.md: -------------------------------------------------------------------------------- 1 | # example-backend 2 | 3 | This package is an EXAMPLE of a Backstage backend. 4 | 5 | The main purpose of this package is to provide a test bed for Backstage plugins 6 | that have a backend part. Feel free to experiment locally or within your fork by 7 | adding dependencies and routes to this backend, to try things out. 8 | 9 | Our goal is to eventually amend the create-app flow of the CLI, such that a 10 | production ready version of a backend skeleton is made alongside the frontend 11 | app. Until then, feel free to experiment here! 12 | 13 | ## Development 14 | 15 | To run the example backend, first go to the project root and run 16 | 17 | ```bash 18 | yarn install 19 | ``` 20 | 21 | You should only need to do this once. 22 | 23 | After that, go to the `packages/backend` directory and run 24 | 25 | ```bash 26 | yarn start 27 | ``` 28 | 29 | If you want to override any configuration locally, for example adding any secrets, 30 | you can do so in `app-config.local.yaml`. 31 | 32 | The backend starts up on port 7007 per default. 33 | 34 | ## Populating The Catalog 35 | 36 | If you want to use the catalog functionality, you need to add so called 37 | locations to the backend. These are places where the backend can find some 38 | entity descriptor data to consume and serve. For more information, see 39 | [Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/#adding-components-to-the-catalog). 40 | 41 | To get started quickly, this template already includes some statically configured example locations 42 | in `app-config.yaml` under `catalog.locations`. You can remove and replace these locations as you 43 | like, and also override them for local development in `app-config.local.yaml`. 44 | 45 | ## Authentication 46 | 47 | We chose [Passport](http://www.passportjs.org/) as authentication platform due 48 | to its comprehensive set of supported authentication 49 | [strategies](http://www.passportjs.org/packages/). 50 | 51 | Read more about the 52 | [auth-backend](https://github.com/backstage/backstage/blob/master/plugins/auth-backend/README.md) 53 | and 54 | [how to add a new provider](https://github.com/backstage/backstage/blob/master/docs/auth/add-auth-provider.md) 55 | 56 | ## Documentation 57 | 58 | - [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md) 59 | - [Backstage Documentation](https://backstage.io/docs) 60 | -------------------------------------------------------------------------------- /app/packages/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "0.0.0", 4 | "main": "dist/index.cjs.js", 5 | "types": "src/index.ts", 6 | "private": true, 7 | "backstage": { 8 | "role": "backend" 9 | }, 10 | "scripts": { 11 | "start": "backstage-cli package start", 12 | "build": "backstage-cli package build", 13 | "lint": "backstage-cli package lint", 14 | "test": "backstage-cli package test", 15 | "clean": "backstage-cli package clean", 16 | "build-image": "docker build ../.. -f Dockerfile --tag backstage" 17 | }, 18 | "dependencies": { 19 | "@backstage/backend-common": "^0.20.0", 20 | "@backstage/backend-tasks": "^0.5.13", 21 | "@backstage/catalog-client": "^1.5.1", 22 | "@backstage/catalog-model": "^1.4.3", 23 | "@backstage/config": "^1.1.1", 24 | "@backstage/plugin-app-backend": "^0.3.56", 25 | "@backstage/plugin-auth-backend": "^0.20.2", 26 | "@backstage/plugin-auth-node": "^0.4.2", 27 | "@backstage/plugin-catalog-backend": "^1.16.0", 28 | "@backstage/plugin-catalog-backend-module-github": "^0.4.6", 29 | "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^0.1.5", 30 | "@backstage/plugin-kubernetes-backend": "^0.14.0", 31 | "@backstage/plugin-permission-common": "^0.7.11", 32 | "@backstage/plugin-permission-node": "^0.7.19", 33 | "@backstage/plugin-proxy-backend": "^0.4.6", 34 | "@backstage/plugin-scaffolder-backend": "^1.19.2", 35 | "@backstage/plugin-search-backend": "^1.4.8", 36 | "@backstage/plugin-search-backend-module-catalog": "^0.1.12", 37 | "@backstage/plugin-search-backend-module-pg": "^0.5.17", 38 | "@backstage/plugin-search-backend-module-techdocs": "^0.1.12", 39 | "@backstage/plugin-search-backend-node": "^1.2.12", 40 | "@backstage/plugin-sonarqube-backend": "^0.2.10", 41 | "@backstage/plugin-techdocs-backend": "^1.9.1", 42 | "@backstage/plugin-todo-backend": "^0.3.6", 43 | "@roadiehq/backstage-plugin-argo-cd-backend": "^2.13.0", 44 | "app": "link:../app", 45 | "better-sqlite3": "^9.0.0", 46 | "dockerode": "^3.3.1", 47 | "express": "^4.17.1", 48 | "express-promise-router": "^4.1.0", 49 | "node-gyp": "^9.0.0", 50 | "pg": "^8.11.3", 51 | "winston": "^3.2.1", 52 | "express-prom-bundle": "^7.0.0", 53 | "prom-client": "^15.0.0" 54 | }, 55 | "devDependencies": { 56 | "@backstage/cli": "^0.25.0", 57 | "@types/dockerode": "^3.3.0", 58 | "@types/express": "^4.17.6", 59 | "@types/express-serve-static-core": "^4.17.5", 60 | "@types/luxon": "^2.0.4" 61 | }, 62 | "files": [ 63 | "dist" 64 | ] 65 | } -------------------------------------------------------------------------------- /app/packages/backend/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { PluginEnvironment } from './types'; 2 | 3 | describe('test', () => { 4 | it('unbreaks the test runner', () => { 5 | const unbreaker = {} as PluginEnvironment; 6 | expect(unbreaker).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /app/packages/backend/src/index.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Hi! 3 | * 4 | * Note that this is an EXAMPLE Backstage backend. Please check the README. 5 | * 6 | * Happy hacking! 7 | */ 8 | 9 | import Router from 'express-promise-router'; 10 | import { 11 | createServiceBuilder, 12 | loadBackendConfig, 13 | getRootLogger, 14 | useHotMemoize, 15 | notFoundHandler, 16 | CacheManager, 17 | DatabaseManager, 18 | HostDiscovery, 19 | UrlReaders, 20 | ServerTokenManager, 21 | } from '@backstage/backend-common'; 22 | import { TaskScheduler } from '@backstage/backend-tasks'; 23 | import { Config } from '@backstage/config'; 24 | import healthcheck from './plugins/healthcheck'; 25 | import app from './plugins/app'; 26 | import auth from './plugins/auth'; 27 | import catalog from './plugins/catalog'; 28 | import scaffolder from './plugins/scaffolder'; 29 | import proxy from './plugins/proxy'; 30 | import techdocs from './plugins/techdocs'; 31 | import sonarqube from './plugins/sonarqube'; 32 | import search from './plugins/search'; 33 | import { PluginEnvironment } from './types'; 34 | import { ServerPermissionClient } from '@backstage/plugin-permission-node'; 35 | import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; 36 | import kubernetes from './plugins/kubernetes'; 37 | import todo from './plugins/todo'; 38 | import { metricsHandler } from './metrics'; 39 | 40 | function makeCreateEnv(config: Config) { 41 | const root = getRootLogger(); 42 | const reader = UrlReaders.default({ logger: root, config }); 43 | const discovery = HostDiscovery.fromConfig(config); 44 | const cacheManager = CacheManager.fromConfig(config); 45 | const databaseManager = DatabaseManager.fromConfig(config, { logger: root }); 46 | const tokenManager = ServerTokenManager.noop(); 47 | const taskScheduler = TaskScheduler.fromConfig(config, { databaseManager }); 48 | 49 | const identity = DefaultIdentityClient.create({ 50 | discovery, 51 | }); 52 | const permissions = ServerPermissionClient.fromConfig(config, { 53 | discovery, 54 | tokenManager, 55 | }); 56 | 57 | root.info(`Created UrlReader ${reader}`); 58 | 59 | return (plugin: string): PluginEnvironment => { 60 | const logger = root.child({ type: 'plugin', plugin }); 61 | const database = databaseManager.forPlugin(plugin); 62 | const cache = cacheManager.forPlugin(plugin); 63 | const scheduler = taskScheduler.forPlugin(plugin); 64 | return { 65 | logger, 66 | database, 67 | cache, 68 | config, 69 | reader, 70 | discovery, 71 | tokenManager, 72 | scheduler, 73 | permissions, 74 | identity, 75 | }; 76 | }; 77 | } 78 | 79 | async function main() { 80 | const config = await loadBackendConfig({ 81 | argv: process.argv, 82 | logger: getRootLogger(), 83 | }); 84 | const createEnv = makeCreateEnv(config); 85 | 86 | const healthcheckEnv = useHotMemoize(module, () => createEnv('healthcheck')); 87 | const catalogEnv = useHotMemoize(module, () => createEnv('catalog')); 88 | const scaffolderEnv = useHotMemoize(module, () => createEnv('scaffolder')); 89 | const authEnv = useHotMemoize(module, () => createEnv('auth')); 90 | const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); 91 | const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); 92 | const searchEnv = useHotMemoize(module, () => createEnv('search')); 93 | const appEnv = useHotMemoize(module, () => createEnv('app')); 94 | const kubernetesEnv = useHotMemoize(module, () => createEnv('kubernetes')); 95 | const todoEnv = useHotMemoize(module, () => createEnv('todo')); 96 | const sonarqubeEnv = useHotMemoize(module, () => createEnv('sonarqube')); 97 | 98 | const apiRouter = Router(); 99 | apiRouter.use('/catalog', await catalog(catalogEnv)); 100 | apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); 101 | apiRouter.use('/auth', await auth(authEnv)); 102 | apiRouter.use('/techdocs', await techdocs(techdocsEnv)); 103 | apiRouter.use('/proxy', await proxy(proxyEnv)); 104 | apiRouter.use('/search', await search(searchEnv)); 105 | apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); 106 | apiRouter.use('/todo', await todo(todoEnv)); 107 | apiRouter.use('/sonarqube', await sonarqube(sonarqubeEnv)); 108 | 109 | // Add backends ABOVE this line; this 404 handler is the catch-all fallback 110 | apiRouter.use(notFoundHandler()); 111 | 112 | const service = createServiceBuilder(module) 113 | .loadConfig(config) 114 | .addRouter('', await healthcheck(healthcheckEnv)) 115 | .addRouter('', metricsHandler()) 116 | .addRouter('/api', apiRouter) 117 | .addRouter('', await app(appEnv)); 118 | 119 | await service.start().catch(err => { 120 | console.log(err); 121 | process.exit(1); 122 | }); 123 | } 124 | 125 | module.hot?.accept(); 126 | main().catch(error => { 127 | console.error('Backend failed to start up', error); 128 | process.exit(1); 129 | }); 130 | -------------------------------------------------------------------------------- /app/packages/backend/src/metrics.ts: -------------------------------------------------------------------------------- 1 | // packages/backend/src/metrics.ts 2 | import { useHotCleanup } from '@backstage/backend-common'; 3 | import { RequestHandler } from 'express'; 4 | import promBundle from 'express-prom-bundle'; 5 | import prom from 'prom-client'; 6 | import * as url from 'url'; 7 | 8 | const rootRegEx = new RegExp('^/([^/]*)/.*'); 9 | const apiRegEx = new RegExp('^/api/([^/]*)/.*'); 10 | 11 | export function normalizePath(req: any): string { 12 | const path = url.parse(req.originalUrl || req.url).pathname || '/'; 13 | 14 | // Capture /api/ and the plugin name 15 | if (apiRegEx.test(path)) { 16 | return path.replace(apiRegEx, '/api/$1'); 17 | } 18 | 19 | // Only the first path segment at root level 20 | return path.replace(rootRegEx, '/$1'); 21 | } 22 | 23 | /** 24 | * Adds a /metrics endpoint, register default runtime metrics and instrument the router. 25 | */ 26 | export function metricsHandler(): RequestHandler { 27 | // We can only initialize the metrics once and have to clean them up between hot reloads 28 | useHotCleanup(module, () => prom.register.clear()); 29 | 30 | return promBundle({ 31 | includeMethod: true, 32 | includePath: true, 33 | // Using includePath alone is problematic, as it will include path labels with high 34 | // cardinality (e.g. path params). Instead we would have to template them. However, this 35 | // is difficult, as every backend plugin might use different routes. Instead we only take 36 | // the first directory of the path, to have at least an idea how each plugin performs: 37 | normalizePath, 38 | promClient: { collectDefaultMetrics: {} }, 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/app.ts: -------------------------------------------------------------------------------- 1 | import { createRouter } from '@backstage/plugin-app-backend'; 2 | import { Router } from 'express'; 3 | import { PluginEnvironment } from '../types'; 4 | 5 | export default async function createPlugin( 6 | env: PluginEnvironment, 7 | ): Promise { 8 | return await createRouter({ 9 | logger: env.logger, 10 | config: env.config, 11 | database: env.database, 12 | appPackageName: 'app', 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/auth.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_NAMESPACE, 3 | stringifyEntityRef, 4 | } from '@backstage/catalog-model'; 5 | import { 6 | createRouter, 7 | providers, 8 | defaultAuthProviderFactories, 9 | } from '@backstage/plugin-auth-backend'; 10 | import { Router } from 'express'; 11 | import { PluginEnvironment } from '../types'; 12 | 13 | export default async function createPlugin( 14 | env: PluginEnvironment, 15 | ): Promise { 16 | return await createRouter({ 17 | logger: env.logger, 18 | config: env.config, 19 | database: env.database, 20 | discovery: env.discovery, 21 | tokenManager: env.tokenManager, 22 | providerFactories: { 23 | ...defaultAuthProviderFactories, 24 | 25 | // This replaces the default GitHub auth provider with a customized one. 26 | // The `signIn` option enables sign-in for this provider, using the 27 | // identity resolution logic that's provided in the `resolver` callback. 28 | // 29 | // This particular resolver makes all users share a single "guest" identity. 30 | // It should only be used for testing and trying out Backstage. 31 | // 32 | // If you want to use a production ready resolver you can switch to 33 | // the one that is commented out below, it looks up a user entity in the 34 | // catalog using the GitHub username of the authenticated user. 35 | // That resolver requires you to have user entities populated in the catalog, 36 | // for example using https://backstage.io/docs/integrations/github/org 37 | // 38 | // There are other resolvers to choose from, and you can also create 39 | // your own, see the auth documentation for more details: 40 | // 41 | // https://backstage.io/docs/auth/identity-resolver 42 | github: providers.github.create({ 43 | signIn: { 44 | async resolver({ result: { fullProfile } }, ctx) { 45 | const userId = fullProfile.username; 46 | if (!userId) { 47 | throw new Error( 48 | `GitHub user profile does not contain a username`, 49 | ); 50 | } 51 | 52 | const userEntityRef = stringifyEntityRef({ 53 | kind: 'User', 54 | name: userId, 55 | namespace: DEFAULT_NAMESPACE, 56 | }); 57 | 58 | return ctx.issueToken({ 59 | claims: { 60 | sub: userEntityRef, 61 | ent: [userEntityRef], 62 | }, 63 | }); 64 | }, 65 | // resolver: providers.github.resolvers.usernameMatchingUserEntityName(), 66 | }, 67 | }), 68 | }, 69 | }); 70 | } 71 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/catalog.ts: -------------------------------------------------------------------------------- 1 | import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; 2 | import { ScaffolderEntitiesProcessor } from '@backstage/plugin-catalog-backend-module-scaffolder-entity-model'; 3 | import { Router } from 'express'; 4 | import { PluginEnvironment } from '../types'; 5 | // import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; 6 | import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github'; 7 | 8 | export default async function createPlugin( 9 | env: PluginEnvironment, 10 | ): Promise { 11 | const builder = await CatalogBuilder.create(env); 12 | builder.addEntityProvider( 13 | GithubEntityProvider.fromConfig(env.config, { 14 | logger: env.logger, 15 | // optional: alternatively, use scheduler with schedule defined in app-config.yaml 16 | schedule: env.scheduler.createScheduledTaskRunner({ 17 | frequency: { minutes: 30 }, 18 | timeout: { minutes: 3 }, 19 | }), 20 | // optional: alternatively, use schedule 21 | scheduler: env.scheduler, 22 | }), 23 | ); 24 | 25 | 26 | builder.addProcessor(new ScaffolderEntitiesProcessor()); 27 | const { processingEngine, router } = await builder.build(); 28 | await processingEngine.start(); 29 | return router; 30 | } 31 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/healthcheck.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 The Backstage Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { createStatusCheckRouter } from '@backstage/backend-common'; 18 | import { Router } from 'express'; 19 | import { PluginEnvironment } from '../types'; 20 | 21 | export default async function createPlugin( 22 | env: PluginEnvironment, 23 | ): Promise { 24 | return await createStatusCheckRouter({ 25 | logger: env.logger, 26 | path: '/healthcheck', 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/kubernetes.ts: -------------------------------------------------------------------------------- 1 | import { KubernetesBuilder } from '@backstage/plugin-kubernetes-backend'; 2 | import { Router } from 'express'; 3 | import { PluginEnvironment } from '../types'; 4 | import { CatalogClient } from '@backstage/catalog-client'; 5 | 6 | export default async function createPlugin( 7 | env: PluginEnvironment, 8 | ): Promise { 9 | const catalogApi = new CatalogClient({ discoveryApi: env.discovery }); 10 | const { router } = await KubernetesBuilder.createBuilder({ 11 | logger: env.logger, 12 | config: env.config, 13 | catalogApi, 14 | permissions: env.permissions, 15 | }).build(); 16 | return router; 17 | } 18 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/proxy.ts: -------------------------------------------------------------------------------- 1 | import { createRouter } from '@backstage/plugin-proxy-backend'; 2 | import { Router } from 'express'; 3 | import { PluginEnvironment } from '../types'; 4 | 5 | export default async function createPlugin( 6 | env: PluginEnvironment, 7 | ): Promise { 8 | return await createRouter({ 9 | logger: env.logger, 10 | config: env.config, 11 | discovery: env.discovery, 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/scaffolder.ts: -------------------------------------------------------------------------------- 1 | import { CatalogClient } from '@backstage/catalog-client'; 2 | import { createRouter } from '@backstage/plugin-scaffolder-backend'; 3 | import { Router } from 'express'; 4 | import type { PluginEnvironment } from '../types'; 5 | 6 | export default async function createPlugin( 7 | env: PluginEnvironment, 8 | ): Promise { 9 | const catalogClient = new CatalogClient({ 10 | discoveryApi: env.discovery, 11 | }); 12 | 13 | return await createRouter({ 14 | logger: env.logger, 15 | config: env.config, 16 | database: env.database, 17 | reader: env.reader, 18 | catalogClient, 19 | identity: env.identity, 20 | permissions: env.permissions, 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/search.ts: -------------------------------------------------------------------------------- 1 | import { useHotCleanup } from '@backstage/backend-common'; 2 | import { createRouter } from '@backstage/plugin-search-backend'; 3 | import { 4 | IndexBuilder, 5 | LunrSearchEngine, 6 | } from '@backstage/plugin-search-backend-node'; 7 | import { PluginEnvironment } from '../types'; 8 | import { DefaultCatalogCollatorFactory } from '@backstage/plugin-search-backend-module-catalog'; 9 | import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-search-backend-module-techdocs'; 10 | import { Router } from 'express'; 11 | 12 | export default async function createPlugin( 13 | env: PluginEnvironment, 14 | ): Promise { 15 | // Initialize a connection to a search engine. 16 | const searchEngine = new LunrSearchEngine({ 17 | logger: env.logger, 18 | }); 19 | const indexBuilder = new IndexBuilder({ 20 | logger: env.logger, 21 | searchEngine, 22 | }); 23 | 24 | const schedule = env.scheduler.createScheduledTaskRunner({ 25 | frequency: { minutes: 10 }, 26 | timeout: { minutes: 15 }, 27 | // A 3 second delay gives the backend server a chance to initialize before 28 | // any collators are executed, which may attempt requests against the API. 29 | initialDelay: { seconds: 3 }, 30 | }); 31 | 32 | // Collators are responsible for gathering documents known to plugins. This 33 | // collator gathers entities from the software catalog. 34 | indexBuilder.addCollator({ 35 | schedule, 36 | factory: DefaultCatalogCollatorFactory.fromConfig(env.config, { 37 | discovery: env.discovery, 38 | tokenManager: env.tokenManager, 39 | }), 40 | }); 41 | 42 | // collator gathers entities from techdocs. 43 | indexBuilder.addCollator({ 44 | schedule, 45 | factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, { 46 | discovery: env.discovery, 47 | logger: env.logger, 48 | tokenManager: env.tokenManager, 49 | }), 50 | }); 51 | 52 | // The scheduler controls when documents are gathered from collators and sent 53 | // to the search engine for indexing. 54 | const { scheduler } = await indexBuilder.build(); 55 | scheduler.start(); 56 | 57 | useHotCleanup(module, () => scheduler.stop()); 58 | 59 | return await createRouter({ 60 | engine: indexBuilder.getSearchEngine(), 61 | types: indexBuilder.getDocumentTypes(), 62 | permissions: env.permissions, 63 | config: env.config, 64 | logger: env.logger, 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/sonarqube.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createRouter, 3 | DefaultSonarqubeInfoProvider, 4 | } from '@backstage/plugin-sonarqube-backend'; 5 | import { Router } from 'express'; 6 | import { PluginEnvironment } from '../types'; 7 | 8 | export default async function createPlugin( 9 | env: PluginEnvironment, 10 | ): Promise { 11 | return await createRouter({ 12 | logger: env.logger, 13 | sonarqubeInfoProvider: DefaultSonarqubeInfoProvider.fromConfig(env.config), 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/techdocs.ts: -------------------------------------------------------------------------------- 1 | import { DockerContainerRunner } from '@backstage/backend-common'; 2 | import { 3 | createRouter, 4 | Generators, 5 | Preparers, 6 | Publisher, 7 | } from '@backstage/plugin-techdocs-backend'; 8 | import Docker from 'dockerode'; 9 | import { Router } from 'express'; 10 | import { PluginEnvironment } from '../types'; 11 | 12 | export default async function createPlugin( 13 | env: PluginEnvironment, 14 | ): Promise { 15 | // Preparers are responsible for fetching source files for documentation. 16 | const preparers = await Preparers.fromConfig(env.config, { 17 | logger: env.logger, 18 | reader: env.reader, 19 | }); 20 | 21 | // Docker client (conditionally) used by the generators, based on techdocs.generators config. 22 | const dockerClient = new Docker(); 23 | const containerRunner = new DockerContainerRunner({ dockerClient }); 24 | 25 | // Generators are used for generating documentation sites. 26 | const generators = await Generators.fromConfig(env.config, { 27 | logger: env.logger, 28 | containerRunner, 29 | }); 30 | 31 | // Publisher is used for 32 | // 1. Publishing generated files to storage 33 | // 2. Fetching files from storage and passing them to TechDocs frontend. 34 | const publisher = await Publisher.fromConfig(env.config, { 35 | logger: env.logger, 36 | discovery: env.discovery, 37 | }); 38 | 39 | // checks if the publisher is working and logs the result 40 | await publisher.getReadiness(); 41 | 42 | return await createRouter({ 43 | preparers, 44 | generators, 45 | publisher, 46 | logger: env.logger, 47 | config: env.config, 48 | discovery: env.discovery, 49 | cache: env.cache, 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /app/packages/backend/src/plugins/todo.ts: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import { CatalogClient } from '@backstage/catalog-client'; 3 | import { 4 | createRouter, 5 | TodoReaderService, 6 | TodoScmReader, 7 | } from '@backstage/plugin-todo-backend'; 8 | import { PluginEnvironment } from '../types'; 9 | 10 | export default async function createPlugin( 11 | env: PluginEnvironment, 12 | ): Promise { 13 | const todoReader = TodoScmReader.fromConfig(env.config, { 14 | logger: env.logger, 15 | reader: env.reader, 16 | }); 17 | 18 | const catalogClient = new CatalogClient({ 19 | discoveryApi: env.discovery, 20 | }); 21 | 22 | const todoService = new TodoReaderService({ 23 | todoReader, 24 | catalogClient, 25 | }); 26 | 27 | return await createRouter({ todoService }); 28 | } 29 | -------------------------------------------------------------------------------- /app/packages/backend/src/types.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from 'winston'; 2 | import { Config } from '@backstage/config'; 3 | import { 4 | PluginCacheManager, 5 | PluginDatabaseManager, 6 | PluginEndpointDiscovery, 7 | TokenManager, 8 | UrlReader, 9 | } from '@backstage/backend-common'; 10 | import { PluginTaskScheduler } from '@backstage/backend-tasks'; 11 | import { PermissionEvaluator } from '@backstage/plugin-permission-common'; 12 | import { IdentityApi } from '@backstage/plugin-auth-node'; 13 | 14 | export type PluginEnvironment = { 15 | logger: Logger; 16 | database: PluginDatabaseManager; 17 | cache: PluginCacheManager; 18 | config: Config; 19 | reader: UrlReader; 20 | discovery: PluginEndpointDiscovery; 21 | tokenManager: TokenManager; 22 | scheduler: PluginTaskScheduler; 23 | permissions: PermissionEvaluator; 24 | identity: IdentityApi; 25 | }; 26 | -------------------------------------------------------------------------------- /app/playwright.config.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 The Backstage Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import { defineConfig } from '@playwright/test'; 18 | import { generateProjects } from '@backstage/e2e-test-utils/playwright'; 19 | 20 | /** 21 | * See https://playwright.dev/docs/test-configuration. 22 | */ 23 | export default defineConfig({ 24 | timeout: 60_000, 25 | 26 | expect: { 27 | timeout: 5_000, 28 | }, 29 | 30 | // Run your local dev server before starting the tests 31 | webServer: process.env.CI 32 | ? [] 33 | : [ 34 | { 35 | command: 'yarn start', 36 | port: 3000, 37 | reuseExistingServer: true, 38 | timeout: 60_000, 39 | }, 40 | ], 41 | 42 | forbidOnly: !!process.env.CI, 43 | 44 | retries: process.env.CI ? 2 : 0, 45 | 46 | reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]], 47 | 48 | use: { 49 | actionTimeout: 0, 50 | baseURL: 51 | process.env.PLAYWRIGHT_URL ?? 52 | (process.env.CI ? 'http://localhost:7007' : 'http://localhost:3000'), 53 | screenshot: 'only-on-failure', 54 | trace: 'on-first-retry', 55 | }, 56 | 57 | outputDir: 'node_modules/.cache/e2e-test-results', 58 | 59 | projects: generateProjects(), // Find all packages with e2e-test folders 60 | }); 61 | -------------------------------------------------------------------------------- /app/plugins/README.md: -------------------------------------------------------------------------------- 1 | # The Plugins Folder 2 | 3 | This is where your own plugins and their associated modules live, each in a 4 | separate folder of its own. 5 | 6 | If you want to create a new plugin here, go to your project root directory, run 7 | the command `yarn new`, and follow the on-screen instructions. 8 | 9 | You can also check out existing plugins on [the plugin marketplace](https://backstage.io/plugins)! 10 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@backstage/cli/config/tsconfig.json", 3 | "include": [ 4 | "packages/*/src", 5 | "plugins/*/src", 6 | "plugins/*/dev", 7 | "plugins/*/migrations" 8 | ], 9 | "exclude": ["node_modules"], 10 | "compilerOptions": { 11 | "outDir": "dist-types", 12 | "rootDir": "." 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /catalog-info.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: backstage.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: backstage-web 5 | description: Backstage Frontend 6 | annotations: 7 | argocd/app-name: backstage-prd 8 | backstage.io/kubernetes-id: backstage 9 | backstage.io/techdocs-ref: dir:. 10 | github.com/project-slug: devxp-tech/backstage 11 | grafana/tag-selector: "Kubernetes" 12 | kubecost.com/deployment-name: "backstage" 13 | prometheus.io/rule: 'sum by (backstage)(changes(kube_pod_status_ready{condition="true"}[5m]))' 14 | prometheus.io/alert: all 15 | sonarqube.org/project-key: backstage 16 | snyk.io/org-name: devxp-tech 17 | snyk.io/project-ids: c3c91d87-e14d-40cd-85c6-141e543350ab 18 | tags: 19 | - web 20 | - frontend 21 | - backstage 22 | links: 23 | - url: https://backstage.devxp-tech.io 24 | title: Backstage 25 | icon: cloud 26 | spec: 27 | type: service 28 | lifecycle: production 29 | owner: group:sre-team 30 | system: backstage 31 | #dependsOn: ['component:bob-cache', 'component:bob-db', 'component:bob-queue'] 32 | apiConsumedBy: ["system:backstage"] 33 | dependsOn: ["resource:backstage-db", "resource:backstage-bucket"] 34 | providesApis: 35 | - backstage 36 | -------------------------------------------------------------------------------- /devspace.yaml: -------------------------------------------------------------------------------- 1 | version: v2beta1 2 | name: backstage 3 | 4 | # `vars` specifies variables which may be used as ${VAR_NAME} in devspace.yaml 5 | vars: 6 | IMAGE: ghcr.io/devxp-tech/backstage 7 | 8 | pipelines: 9 | # Override the default pipeline for 'devspace dev' 10 | dev: 11 | run: |- 12 | run_dependencies --all # 1. Deploy any projects this project needs (see "dependencies") 13 | create_deployments --all # 2. Deploy Helm charts and manifests specfied as "deployments" 14 | start_dev --all # 3. Start dev mode "app" (see "dev" section 15 | 16 | # This is a list of `images` that DevSpace can build for this project 17 | # We recommend to skip image building during development (devspace dev) as much as possible 18 | images: 19 | app: 20 | image: ${IMAGE} 21 | dockerfile: ./Dockerfile 22 | build: 23 | disabled: true 24 | # createPullSecret: true 25 | 26 | # This is a list of `deployments` that DevSpace can create for this project 27 | deployments: 28 | app: 29 | helm: 30 | chart: 31 | name: devxp-dev 32 | version: 0.0.3 33 | repo: https://devxp-tech.github.io/helm-charts 34 | values: 35 | name: backstage 36 | serviceAccount: 37 | name: backstage 38 | service: 39 | port: 3000 40 | container: 41 | port: 7007 42 | envs: 43 | - name: POSTGRES_HOST 44 | value: db-postgresql 45 | - name: POSTGRES_PORT 46 | value: 5432 47 | - name: POSTGRES_USER 48 | value: ${POSTGRES_USER} 49 | - name: POSTGRES_PASSWORD 50 | value: ${POSTGRES_PASSWORD} 51 | - name: POSTGRES_DATABASE 52 | value: backstage 53 | - name: PGDATABASE 54 | value: backstage 55 | - name: ARGOCD_AUTH_TOKEN 56 | value: ${ARGOCD_AUTH_TOKEN} 57 | - name: AUTH_GITHUB_CLIENT_ID 58 | value: ${AUTH_GITHUB_CLIENT_ID} 59 | - name: AUTH_GITHUB_CLIENT_SECRET 60 | value: ${AUTH_GITHUB_CLIENT_SECRET} 61 | - name: ENV 62 | value: development 63 | - name: GITHUB_ACCESS_TOKEN 64 | value: ${GITHUB_ACCESS_TOKEN} 65 | - name: GIT_DISCOVERY_ACROSS_FILESYSTEM 66 | value: 1 67 | - name: GRAFANA_TOKEN 68 | value: ${GRAFANA_TOKEN} 69 | - name: GITHUB_TOKEN 70 | value: ${GITHUB_TOKEN} 71 | - name: K8S_TOKEN 72 | value: ${K8S_TOKEN} 73 | - name: K8S_URL 74 | value: ${K8S_URL} 75 | - name: SONARQUBE_TOKEN 76 | value: ${SONARQUBE_TOKEN} 77 | - name: TECHDOCS_BUCKET 78 | value: ${TECHDOCS_BUCKET} 79 | resources: 80 | requests: 81 | cpu: "100m" 82 | memory: "256Mi" 83 | limits: 84 | cpu: "200m" 85 | memory: "512Mi" 86 | db: 87 | helm: 88 | chart: 89 | name: postgresql 90 | version: 12.2.1 91 | repo: https://charts.bitnami.com/bitnami 92 | values: 93 | global: 94 | postgresql: 95 | auth: 96 | username: ${POSTGRES_USER} 97 | password: ${POSTGRES_PASSWORD} 98 | postgresPassword: ${POSTGRES_PASSWORD} 99 | database: "backstage" 100 | auth: 101 | username: ${POSTGRES_USER} 102 | password: ${POSTGRES_PASSWORD} 103 | postgresPassword: ${POSTGRES_PASSWORD} 104 | database: "backstage" 105 | 106 | # This is a list of `dev` containers that are based on the containers created by your deployments 107 | dev: 108 | app: 109 | # Search for the container that runs this image 110 | imageSelector: ${IMAGE} 111 | # Replace the container image with this dev-optimized image (allows to skip image building during development) 112 | devImage: ghcr.io/loft-sh/devspace-containers/javascript:18-alpine 113 | logs: {} 114 | # command: ["node", "packages/backend", "--config", "app-config.yaml"] 115 | workingDir: /app 116 | # Sync files between the local filesystem and the development container 117 | sync: 118 | - path: ./app:/app 119 | excludePaths: 120 | - .git/ 121 | uploadExcludePaths: 122 | - Dockerfile 123 | - target/ 124 | - .git/ 125 | uploadExcludeFile: .dockerignore 126 | # onUpload: 127 | # restartContainer: true 128 | terminal: 129 | command: ./devspace_start.sh 130 | # Forward the following ports to be able access your application via localhost 131 | ports: 132 | - port: 23450:2345 133 | # - port: 3000:3000 134 | - port: 7007:7007 135 | # Open the following URLs once they return an HTTP status code other than 502 or 503 136 | open: 137 | - url: http://backstage.local:7007 138 | - url: http://localhost:8090 139 | 140 | # Use the `commands` section to define repeatable dev workflows for this project 141 | commands: 142 | migrate-db: 143 | command: |- 144 | echo 'This is a cross-platform, shared command that can be used to codify any kind of dev task.' 145 | echo 'Anyone using this project can invoke it via "devspace run migrate-db"' 146 | test: 147 | command: |- 148 | go test -v ./... 149 | 150 | # Define dependencies to other projects with a devspace.yaml 151 | # dependencies: 152 | # homepage: 153 | # git: https://github.com/devxp-tech/homepage 154 | # branch: main 155 | # pipeline: dev 156 | 157 | ## Teste 158 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | app: 4 | &defaults 5 | command: sh -c 'yarn dev' 6 | hostname: backstage.local 7 | platform: linux/amd64 8 | image: backstage:dev 9 | build: 10 | context: . 11 | target: dev 12 | working_dir: /app 13 | volumes: 14 | - ./app:/app 15 | ports: 16 | - 3000:3000 17 | - 7007:7007 18 | environment: 19 | - ARGOCD_AUTH_TOKEN=$ARGOCD_AUTH_TOKEN 20 | - AUTH_GITHUB_CLIENT_ID=$AUTH_GITHUB_CLIENT_ID 21 | - AUTH_GITHUB_CLIENT_SECRET=$AUTH_GITHUB_CLIENT_SECRET 22 | - ENV=development 23 | - GITHUB_ACCESS_TOKEN=$GITHUB_ACCESS_TOKEN 24 | - GIT_DISCOVERY_ACROSS_FILESYSTEM=1 25 | - GRAFANA_TOKEN=$GRAFANA_TOKEN 26 | - K8S_TOKEN=$K8S_TOKEN 27 | - K8S_URL=$K8S_URL 28 | - PGDATABASE=backstage 29 | - POSTGRES_DATABASE=backstage 30 | - POSTGRES_HOST=postgres 31 | - POSTGRES_PASSWORD=postgres 32 | - POSTGRES_PORT=5432 33 | - POSTGRES_USER=postgres 34 | - SONARQUBE_TOKEN=$SONARQUBE_TOKEN 35 | - TECHDOCS_BUCKET=$TECHDOCS_BUCKET 36 | - AWS_ACCESS_KEY_ID=$TECHDOCS_AWS_ACCESS_KEY_ID 37 | - AWS_SECRET_ACCESS_KEY=$TECHDOCS_AWS_SECRET_ACCESS_KEY 38 | - AWS_REGION=us-east-1 39 | depends_on: 40 | - postgres 41 | 42 | prd: 43 | <<: *defaults 44 | image: backstage:prd-local 45 | build: 46 | context: . 47 | volumes: [] 48 | command: sh -c "node packages/backend --config app-config.yaml" 49 | 50 | cmd: 51 | <<: *defaults 52 | working_dir: /app 53 | volumes: 54 | - ./app:/app 55 | 56 | test: 57 | <<: *defaults 58 | command: 'yarn test:all' 59 | # command: 'yarn tsc' 60 | environment: 61 | - ENVIRONMENT=development 62 | volumes: 63 | - ./app:/app 64 | 65 | postgres: 66 | image: postgres:latest 67 | environment: 68 | - POSTGRES_PASSWORD=postgres 69 | - POSTGRES_USER=postgres 70 | - POSTGRES_DB=backstage 71 | - PGDATA=/var/lib/postgresql/data 72 | volumes: 73 | - pgdata:/var/lib/postgresql/data 74 | ports: 75 | - 5432:5432 76 | 77 | volumes: 78 | pgdata: {} 79 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Backstage Documentation 2 | 3 | This is a basic example of documentation. 4 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: "backstage-web" 2 | site_description: "Main documentation for Backstage features and platform APIs" 3 | repo_url: https://github.com/devxp-tech/backstage 4 | edit_uri: edit/main/docs 5 | 6 | plugins: 7 | - techdocs-core 8 | 9 | nav: 10 | - Getting Started: 11 | - Getting Started: "docs/index.md" 12 | -------------------------------------------------------------------------------- /techstack.yml: -------------------------------------------------------------------------------- 1 | repo_name: devxp-tech/backstage 2 | report_id: 7ec31176c0708f2a7d99fca8952d6363 3 | version: 0.1 4 | repo_type: Public 5 | timestamp: '2024-03-15T10:25:36+00:00' 6 | requested_by: diegoluisi 7 | provider: github 8 | branch: main 9 | detected_tools_count: 36 10 | tools: 11 | - name: TypeScript 12 | description: A superset of JavaScript that compiles to clean JavaScript output 13 | website_url: http://www.typescriptlang.org 14 | license: Apache-2.0 15 | open_source: true 16 | hosted_saas: false 17 | category: Languages & Frameworks 18 | sub_category: Languages 19 | image_url: https://img.stackshare.io/service/1612/bynNY5dJ.jpg 20 | detection_source_url: https://github.com/devxp-tech/backstage 21 | detection_source: Repo Metadata 22 | - name: JavaScript 23 | description: Lightweight, interpreted, object-oriented language with first-class 24 | functions 25 | website_url: https://developer.mozilla.org/en-US/docs/Web/JavaScript 26 | open_source: true 27 | hosted_saas: false 28 | category: Languages & Frameworks 29 | sub_category: Languages 30 | image_url: https://img.stackshare.io/service/1209/javascript.jpeg 31 | detection_source_url: https://github.com/devxp-tech/backstage 32 | detection_source: Repo Metadata 33 | - name: ExpressJS 34 | description: Sinatra inspired web development framework for node.js -- insanely 35 | fast, flexible, and simple 36 | website_url: http://expressjs.com/ 37 | version: 4.18.2 38 | license: MIT 39 | open_source: true 40 | hosted_saas: false 41 | category: Languages & Frameworks 42 | sub_category: Microframeworks (Backend) 43 | image_url: https://img.stackshare.io/service/1163/hashtag.png 44 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 45 | detection_source: app/packages/backend/package.json 46 | last_updated_by: Diego Luisi 47 | last_updated_on: 2022-05-26 18:06:44.000000000 Z 48 | - name: Material-UI 49 | description: Material UI is a library of React UI components that implements Google's 50 | Material Design. 51 | website_url: https://github.com/mui/material-ui 52 | license: MIT 53 | open_source: true 54 | hosted_saas: false 55 | category: Languages & Frameworks 56 | sub_category: Front-End Frameworks 57 | image_url: https://img.stackshare.io/service/1904/default_44d81cb9fadbc3688b7e91a6d5217d0ea5358b57.png 58 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/packages/app/package.json 59 | detection_source: app/packages/app/package.json 60 | last_updated_by: Diego Luisi 61 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 62 | - name: Node.js 63 | description: A platform built on Chrome's JavaScript runtime for easily building 64 | fast, scalable network applications 65 | website_url: http://nodejs.org/ 66 | version: 20.0.0 67 | open_source: true 68 | hosted_saas: false 69 | category: Languages & Frameworks 70 | sub_category: Frameworks (Full Stack) 71 | image_url: https://img.stackshare.io/service/1011/n1JRsFeB_400x400.png 72 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/Dockerfile 73 | detection_source: Dockerfile 74 | last_updated_by: Gritzko Daniel Kleiner 75 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 76 | - name: React 77 | description: A JavaScript library for building user interfaces 78 | website_url: https://reactjs.org/ 79 | version: 17.0.2 80 | license: MIT 81 | open_source: true 82 | hosted_saas: false 83 | category: Libraries 84 | sub_category: Javascript UI Libraries 85 | image_url: https://img.stackshare.io/service/1020/OYIaJ1KK.png 86 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 87 | detection_source: app/package.json 88 | last_updated_by: Diego Luisi 89 | last_updated_on: 2023-07-21 20:22:53.000000000 Z 90 | - name: React Router 91 | description: A complete routing solution for React.js 92 | website_url: https://github.com/rackt/react-router 93 | version: 6.21.1 94 | license: MIT 95 | open_source: true 96 | hosted_saas: false 97 | category: Libraries 98 | sub_category: JavaScript Framework Components 99 | image_url: https://img.stackshare.io/service/3350/8261421.png 100 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 101 | detection_source: app/packages/app/package.json 102 | last_updated_by: Gritzko Daniel Kleiner 103 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 104 | - name: PostgreSQL 105 | description: A powerful, open source object-relational database system 106 | website_url: http://www.postgresql.org/ 107 | open_source: true 108 | hosted_saas: false 109 | category: Data Stores 110 | sub_category: Databases 111 | image_url: https://img.stackshare.io/service/1028/ASOhU5xJ.png 112 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/packages/backend/package.json 113 | detection_source: app/packages/backend/package.json 114 | last_updated_by: Diego Luisi 115 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 116 | - name: Backstage.io 117 | description: An open platform for building developer portals 118 | website_url: https://backstage.io/ 119 | license: Apache-2.0 120 | open_source: true 121 | hosted_saas: false 122 | category: Build, Test, Deploy 123 | sub_category: Microservice Catalog 124 | image_url: https://img.stackshare.io/service/25383/default_8c8908fec7692e3304706fa3ca1d6bac174b6885.png 125 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/docker-compose.yml 126 | detection_source: docker-compose.yml 127 | last_updated_by: Diego Luisi 128 | last_updated_on: 2023-12-27 21:37:12.000000000 Z 129 | - name: Docker 130 | description: Enterprise Container Platform for High-Velocity Innovation. 131 | website_url: https://www.docker.com/ 132 | license: Apache-2.0 133 | open_source: true 134 | hosted_saas: false 135 | category: Build, Test, Deploy 136 | sub_category: Virtual Machine Platforms & Containers 137 | image_url: https://img.stackshare.io/service/586/n4u37v9t_400x400.png 138 | detection_source_url: https://github.com/devxp-tech/backstage 139 | detection_source: Repo Metadata 140 | - name: Git 141 | description: Fast, scalable, distributed revision control system 142 | website_url: http://git-scm.com/ 143 | open_source: true 144 | hosted_saas: false 145 | category: Build, Test, Deploy 146 | sub_category: Version Control System 147 | image_url: https://img.stackshare.io/service/1046/git.png 148 | detection_source_url: https://github.com/devxp-tech/backstage 149 | detection_source: Repo Metadata 150 | - name: GitHub Actions 151 | description: Automate your workflow from idea to production 152 | website_url: https://github.com/features/actions 153 | open_source: false 154 | hosted_saas: true 155 | category: Build, Test, Deploy 156 | sub_category: Continuous Integration 157 | image_url: https://img.stackshare.io/service/11563/actions.png 158 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/.github/workflows/auto-assign.yaml 159 | detection_source: ".github/workflows/auto-assign.yaml" 160 | last_updated_by: Diego Luisi 161 | last_updated_on: 2023-05-30 09:31:08.000000000 Z 162 | - name: Prettier 163 | description: Prettier is an opinionated code formatter. 164 | website_url: https://prettier.io/ 165 | version: 2.8.8 166 | license: MIT 167 | open_source: true 168 | hosted_saas: false 169 | category: Build, Test, Deploy 170 | sub_category: Code Review 171 | image_url: https://img.stackshare.io/service/7035/default_66f265943abed56bcdbfca1c866a4261b1fbb063.jpg 172 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 173 | detection_source: app/package.json 174 | last_updated_by: Gritzko Daniel Kleiner 175 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 176 | - name: Yarn 177 | description: A new package manager for JavaScript 178 | website_url: https://yarnpkg.com/ 179 | open_source: true 180 | hosted_saas: false 181 | category: Build, Test, Deploy 182 | sub_category: Front End Package Manager 183 | image_url: https://img.stackshare.io/service/5848/44mC-kJ3.jpg 184 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/.yarnrc 185 | detection_source: app/.yarnrc 186 | last_updated_by: Diego Luisi 187 | last_updated_on: 2024-01-03 15:06:16.000000000 Z 188 | - name: npm 189 | description: The package manager for JavaScript. 190 | website_url: https://www.npmjs.com/ 191 | open_source: false 192 | hosted_saas: false 193 | category: Build, Test, Deploy 194 | sub_category: Front End Package Manager 195 | image_url: https://img.stackshare.io/service/1120/lejvzrnlpb308aftn31u.png 196 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/packages/backend/package.json 197 | detection_source: app/packages/backend/package.json 198 | last_updated_by: Diego Luisi 199 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 200 | - name: Lerna 201 | description: A tool for managing JavaScript projects 202 | website_url: https://lerna.js.org/ 203 | version: 7.4.2 204 | license: MIT 205 | open_source: true 206 | hosted_saas: false 207 | category: Libraries 208 | sub_category: Javascript Utilities & Libraries 209 | image_url: https://img.stackshare.io/service/6207/OwqAUSQi_400x400.jpg 210 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 211 | detection_source: app/package.json 212 | last_updated_by: Gritzko Daniel Kleiner 213 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 214 | - name: Shell 215 | description: A shell is a text-based terminal, used for manipulating programs and 216 | files. Shell scripts typically manage program execution. 217 | website_url: https://en.wikipedia.org/wiki/Shell_script 218 | open_source: false 219 | hosted_saas: false 220 | category: Languages & Frameworks 221 | sub_category: Languages 222 | image_url: https://img.stackshare.io/service/4631/default_c2062d40130562bdc836c13dbca02d318205a962.png 223 | detection_source_url: https://github.com/devxp-tech/backstage 224 | detection_source: Repo Metadata 225 | - name: Winston 226 | description: a multi-transport async logging library for node.js 227 | website_url: https://github.com/winstonjs/winston 228 | open_source: false 229 | hosted_saas: false 230 | image_url: https://img.stackshare.io/service/6668/9682013.png 231 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/packages/backend/package.json 232 | detection_source: app/packages/backend/package.json 233 | last_updated_by: Diego Luisi 234 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 235 | - name: "@material-ui/core" 236 | description: React components that implement Google's Material Design 237 | package_url: https://www.npmjs.com/@material-ui/core 238 | version: 4.12.4 239 | license: MIT 240 | open_source: true 241 | hosted_saas: false 242 | category: Libraries 243 | sub_category: npm Packages 244 | image_url: https://img.stackshare.io/package/16271/default_f04d39fc656c2e32ee1b9d3875a3002459aa3b69.png 245 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 246 | detection_source: app/packages/app/package.json 247 | last_updated_by: Gritzko Daniel Kleiner 248 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 249 | - name: "@material-ui/icons" 250 | description: Material Design Svg Icons converted to Material-UI React components 251 | package_url: https://www.npmjs.com/@material-ui/icons 252 | version: 4.11.3 253 | license: MIT 254 | open_source: true 255 | hosted_saas: false 256 | category: Libraries 257 | sub_category: npm Packages 258 | image_url: https://img.stackshare.io/package/16471/default_73c88a18b684e01cbdbf945631a40a44aff5a777.png 259 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 260 | detection_source: app/packages/app/package.json 261 | last_updated_by: Diego Luisi 262 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 263 | - name: "@testing-library/jest-dom" 264 | description: Custom jest matchers to test the state of the DOM 265 | package_url: https://www.npmjs.com/@testing-library/jest-dom 266 | version: 5.17.0 267 | license: MIT 268 | open_source: true 269 | hosted_saas: false 270 | category: Libraries 271 | sub_category: npm Packages 272 | image_url: https://img.stackshare.io/package/17424/default_1cdcda15ebb7caed879f8340bc212b44c4ec9dac.png 273 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 274 | detection_source: app/packages/app/package.json 275 | last_updated_by: Gritzko Daniel Kleiner 276 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 277 | - name: "@testing-library/react" 278 | description: Simple and complete React DOM testing utilities that encourage good 279 | testing practices 280 | package_url: https://www.npmjs.com/@testing-library/react 281 | version: 12.1.5 282 | license: MIT 283 | open_source: true 284 | hosted_saas: false 285 | category: Libraries 286 | sub_category: npm Packages 287 | image_url: https://img.stackshare.io/package/16549/default_d522554c6a41cb28d922d6d3ad32ad4afa0e3bb5.png 288 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 289 | detection_source: app/packages/app/package.json 290 | last_updated_by: Gritzko Daniel Kleiner 291 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 292 | - name: "@types/express" 293 | description: TypeScript definitions for Express 294 | package_url: https://www.npmjs.com/@types/express 295 | version: 4.17.21 296 | license: MIT 297 | open_source: true 298 | hosted_saas: false 299 | category: Libraries 300 | sub_category: npm Packages 301 | image_url: https://img.stackshare.io/package/16100/default_d947c1690e032a288145c7e2491999eab3ea8ede.png 302 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 303 | detection_source: app/packages/backend/package.json 304 | last_updated_by: Gritzko Daniel Kleiner 305 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 306 | - name: "@types/react" 307 | description: TypeScript definitions for React 308 | package_url: https://www.npmjs.com/@types/react 309 | version: 17.0.74 310 | license: MIT 311 | open_source: true 312 | hosted_saas: false 313 | category: Libraries 314 | sub_category: npm Packages 315 | image_url: https://img.stackshare.io/package/15894/default_1d65e37e65b7f80761374f0202776043277d505d.png 316 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 317 | detection_source: app/package.json 318 | last_updated_by: Gritzko Daniel Kleiner 319 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 320 | - name: "@types/react-dom" 321 | description: TypeScript definitions for React 322 | package_url: https://www.npmjs.com/@types/react-dom 323 | version: 17.0.25 324 | license: MIT 325 | open_source: true 326 | hosted_saas: false 327 | category: Libraries 328 | sub_category: npm Packages 329 | image_url: https://img.stackshare.io/package/15946/default_54b691c123fc8979741e800e4dcd3936c0f3b246.png 330 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 331 | detection_source: app/packages/app/package.json 332 | last_updated_by: Gritzko Daniel Kleiner 333 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 334 | - name: concurrently 335 | description: Run commands concurrently 336 | package_url: https://www.npmjs.com/concurrently 337 | version: 8.2.2 338 | license: MIT 339 | open_source: true 340 | hosted_saas: false 341 | category: Libraries 342 | sub_category: npm Packages 343 | image_url: https://img.stackshare.io/package/16041/default_5fd43aeff4d6a935abc13737de01a0355210499d.png 344 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 345 | detection_source: app/package.json 346 | last_updated_by: Gritzko Daniel Kleiner 347 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 348 | - name: cross-env 349 | description: Run scripts that set and use environment variables across platforms 350 | package_url: https://www.npmjs.com/cross-env 351 | version: 7.0.3 352 | license: MIT 353 | open_source: true 354 | hosted_saas: false 355 | category: Libraries 356 | sub_category: npm Packages 357 | image_url: https://img.stackshare.io/package/15828/default_14fd11531839d935f920b6d55bd6f3528c890ad7.png 358 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 359 | detection_source: app/packages/app/package.json 360 | last_updated_by: Gritzko Daniel Kleiner 361 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 362 | - name: dockerode 363 | description: Docker Remote API module 364 | package_url: https://www.npmjs.com/dockerode 365 | version: 3.3.5 366 | license: Apache-2.0 367 | open_source: true 368 | hosted_saas: false 369 | category: Libraries 370 | sub_category: npm Packages 371 | image_url: https://img.stackshare.io/package/17460/default_2ae5beb193365eca46e337162957275ebc9c6b3b.png 372 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 373 | detection_source: app/packages/backend/package.json 374 | last_updated_by: Diego Luisi 375 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 376 | - name: express 377 | description: Fast, unopinionated, minimalist web framework 378 | package_url: https://www.npmjs.com/express 379 | version: 4.18.2 380 | license: MIT 381 | open_source: true 382 | hosted_saas: false 383 | category: Libraries 384 | sub_category: npm Packages 385 | image_url: https://img.stackshare.io/package/15818/default_db4a7791d2f1174547374b9b587bc10fec088a5a.png 386 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 387 | detection_source: app/packages/backend/package.json 388 | last_updated_by: Diego Luisi 389 | last_updated_on: 2022-05-26 18:06:44.000000000 Z 390 | - name: history 391 | description: Manage session history with JavaScript 392 | package_url: https://www.npmjs.com/history 393 | version: 5.3.0 394 | license: MIT 395 | open_source: true 396 | hosted_saas: false 397 | category: Libraries 398 | sub_category: npm Packages 399 | image_url: https://img.stackshare.io/package/16209/default_dc80ff0a17bac19253430a4f0f586714841116db.png 400 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 401 | detection_source: app/packages/app/package.json 402 | last_updated_by: Diego Luisi 403 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 404 | - name: node-gyp 405 | description: Node.js native addon build tool 406 | package_url: https://www.npmjs.com/node-gyp 407 | version: 9.4.1 408 | license: MIT 409 | open_source: true 410 | hosted_saas: false 411 | category: Libraries 412 | sub_category: npm Packages 413 | image_url: https://img.stackshare.io/package/16669/default_6dad4e42e12d47cc6edfbdea036dae12f91abebb.png 414 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 415 | detection_source: app/package.json 416 | last_updated_by: Gritzko Daniel Kleiner 417 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 418 | - name: pg 419 | description: PostgreSQL client - pure javascript & libpq with the same API 420 | package_url: https://www.npmjs.com/pg 421 | version: 8.11.3 422 | license: MIT 423 | open_source: true 424 | hosted_saas: false 425 | category: Libraries 426 | sub_category: npm Packages 427 | image_url: https://img.stackshare.io/package/16197/default_3d197518f6bb529bfcc1b685e2cefbdfe83ff108.png 428 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 429 | detection_source: app/packages/backend/package.json 430 | last_updated_by: Diego Luisi 431 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 432 | - name: react-dom 433 | description: React package for working with the DOM 434 | package_url: https://www.npmjs.com/react-dom 435 | version: 17.0.2 436 | license: MIT 437 | open_source: true 438 | hosted_saas: false 439 | category: Libraries 440 | sub_category: npm Packages 441 | image_url: https://img.stackshare.io/package/15808/default_14fd11531839d935f920b6d55bd6f3528c890ad7.png 442 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 443 | detection_source: app/packages/app/package.json 444 | last_updated_by: Gritzko Daniel Kleiner 445 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 446 | - name: react-router 447 | description: A complete routing library for React 448 | package_url: https://www.npmjs.com/react-router 449 | version: 6.21.1 450 | license: MIT 451 | open_source: true 452 | hosted_saas: false 453 | category: Libraries 454 | sub_category: npm Packages 455 | image_url: https://img.stackshare.io/package/16058/default_261820f5687b4c88a3e8f95c71b5e8dccd34c1d7.png 456 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 457 | detection_source: app/packages/app/package.json 458 | last_updated_by: Gritzko Daniel Kleiner 459 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 460 | - name: react-router-dom 461 | description: DOM bindings for React Router 462 | package_url: https://www.npmjs.com/react-router-dom 463 | version: 6.21.1 464 | license: MIT 465 | open_source: true 466 | hosted_saas: false 467 | category: Libraries 468 | sub_category: npm Packages 469 | image_url: https://img.stackshare.io/package/16025/default_e25d1fbb04a118c79fb444294461417342bd03bf.png 470 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 471 | detection_source: app/packages/app/package.json 472 | last_updated_by: Gritzko Daniel Kleiner 473 | last_updated_on: 2023-12-26 19:52:09.000000000 Z 474 | - name: winston 475 | description: A logger for just about everything 476 | package_url: https://www.npmjs.com/winston 477 | version: 3.11.0 478 | license: MIT 479 | open_source: true 480 | hosted_saas: false 481 | category: Libraries 482 | sub_category: npm Packages 483 | image_url: https://img.stackshare.io/package/16003/default_261820f5687b4c88a3e8f95c71b5e8dccd34c1d7.png 484 | detection_source_url: https://github.com/devxp-tech/backstage/blob/main/app/yarn.lock 485 | detection_source: app/packages/backend/package.json 486 | last_updated_by: Diego Luisi 487 | last_updated_on: 2022-05-02 14:26:57.000000000 Z 488 | --------------------------------------------------------------------------------