Conversation
|
This pull request fixes 24 alerts when merging 20aed48 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 4e87744 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging bd6a33e into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging d2cecbd into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging a36f68c into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 3cde989 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 6a168cb into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 0e1bd29 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging ce2993e into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 5cb5e66 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging aa94aa1 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging a42665b into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 1d924e9 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 51602ec into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 4520f1f into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 1c097d7 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 3daa64a into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging b89c3f9 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 3726e6e into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 1e5a05c into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 1b0a87d into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging b5c7c9c into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 695e9a8 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 37a5855 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 41b7bed into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 166301b into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 2fe71b3 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 77a8995 into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging 32307dc into 4ceee58 - view on LGTM.com fixed alerts:
|
|
This pull request fixes 24 alerts when merging e38b8f1 into 4ceee58 - view on LGTM.com fixed alerts:
|
feat: Add support for FEATHER extension
fix: Fix lxd port mapping; reduce log of jobs
Feature adding guest role and settings to make datasets public
…ortal into global_daily
change guest middleware from blocklist to allowlist
…ortal into global_daily
feat: Add guest role and settings to make datasets public
# Conflicts: # packages/itmat-commons/src/index.ts # packages/itmat-commons/src/permissions.ts # packages/itmat-interface/src/graphql/core/permissionCore.ts # packages/itmat-interface/src/graphql/resolvers/fileResolvers.ts # packages/itmat-interface/src/graphql/resolvers/jobResolvers.ts # packages/itmat-interface/src/graphql/resolvers/permissionResolvers.ts # packages/itmat-interface/src/graphql/resolvers/studyResolvers.ts # packages/itmat-interface/src/rest/fileDownload.ts # packages/itmat-interface/test/GraphQLTests/file.test.ts # packages/itmat-interface/test/serverTests/job.test.ts # packages/itmat-interface/test/serverTests/permission.test.ts # packages/itmat-interface/test/serverTests/study.test.ts # packages/itmat-ui-react/src/components/reusable/roleControlSection/roleControlSection.tsx # yarn.lock
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| matrix: | ||
| os: [ubuntu-latest] | ||
| node: [20.x] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Derive appropriate SHAs for base and head for `nx affected` commands | ||
| uses: nrwl/nx-set-shas@v4 | ||
| with: | ||
| main-branch-name: master | ||
| error-on-no-successful-workflow: true | ||
|
|
||
| - run: | | ||
| echo "Nx base: ${{ env.NX_BASE }}" | ||
| echo "Git head: ${{ env.NX_HEAD }}" | ||
|
|
||
| - name: Using Node.js ${{ matrix.node }} | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: ${{ matrix.node }} | ||
| cache: yarn | ||
|
|
||
| - name: Disable TCP/UDP Offloading | ||
| shell: bash | ||
| run: | | ||
| if [ "$RUNNER_OS" == "Linux" ]; then | ||
| sudo ethtool -K eth0 tx off rx off | ||
| exit 0 | ||
| elif [ "$RUNNER_OS" == "macOS" ]; then | ||
| sudo sysctl -w net.link.generic.system.hwcksum_tx=0 | ||
| sudo sysctl -w net.link.generic.system.hwcksum_rx=0 | ||
| exit 0 | ||
| else | ||
| echo "$RUNNER_OS not supported" | ||
| exit 0 | ||
| fi | ||
|
|
||
| - name: Installing dependencies | ||
| run: | | ||
| yarn install --network-timeout 1000000 --forzen-lockfile | ||
|
|
||
| - name: Checking for lint | ||
| run: | | ||
| yarn run nx affected --target=lint --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} | ||
|
|
||
| - name: Building packages | ||
| run: | | ||
| yarn run nx affected --target=build --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --parallel=1 | ||
|
|
||
| - name: Running unit tests | ||
| run: | | ||
| yarn run nx affected --target=test --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --parallel=1 | ||
| env: | ||
| CI: true | ||
|
|
||
| # email_test: | ||
| # runs-on: itmat | ||
| # strategy: | ||
| # matrix: | ||
| # node: [10.x, 12.x] | ||
| # steps: | ||
| # - uses: actions/checkout@v1 | ||
| # - name: Using Node.js ${{ matrix.node }} | ||
| # uses: actions/setup-node@v1 | ||
| # with: | ||
| # node-version: ${{ matrix.node }} | ||
| # - name: Installing dependencies | ||
| # run: yarn install | ||
| # - name: Checking for lint | ||
| # run: yarn run lint | ||
| # - name: Building packages | ||
| # run: yarn run build | ||
| # - name: Running unit tests | ||
| # run: yarn run test | ||
| # env: | ||
| # CI: true | ||
| # TEST_SMTP_CRED: ${{ secrets.TEST_SMTP_CRED }} | ||
| # TEST_SMTP_USERNAME: ${{ secrets.TEST_SMTP_USERNAME }} | ||
| # TEST_RECEIVER_EMAIL_ADDR: ${{ secrets.TEST_RECEIVER_EMAIL_ADDR }} |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The best way to fix this problem is to add a permissions: block at the appropriate scope to the workflow YAML, specifying only the minimum required permissions. Since this workflow does not appear to require any ability to modify repository contents, and only needs to read source code, you should set contents: read, either at the root level (affecting all jobs), or inside the build job (if you later add other jobs requiring different permissions). For this workflow, root-level is best. The change is to insert a block:
permissions:
contents: read...directly after the workflow name: and before the on: trigger in .github/workflows/99_ci.yml. No other imports/methods/definitions are needed.
| @@ -1,4 +1,6 @@ | ||
| name: Test and Build CI | ||
| permissions: | ||
| contents: read | ||
|
|
||
| on: [push] | ||
|
|
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| # We must fetch at least the immediate parents so that if this is | ||
| # a pull request then we can checkout the head. | ||
| fetch-depth: 2 | ||
|
|
||
| # Initializes the CodeQL tools for scanning. | ||
| - name: Initialize CodeQL | ||
| uses: github/codeql-action/init@v3 | ||
| # Override language selection by uncommenting this and choosing your languages | ||
| # with: | ||
| # languages: go, javascript, csharp, python, cpp, java | ||
|
|
||
| # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). | ||
| # If this step fails, then you should remove it and run the build manually (see below) | ||
| - name: Autobuild | ||
| uses: github/codeql-action/autobuild@v3 | ||
|
|
||
| # ℹ️ Command-line programs to run using the OS shell. | ||
| # 📚 https://git.io/JvXDl | ||
|
|
||
| # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines | ||
| # and modify them (or add more) to build your code if your project | ||
| # uses a compiled language | ||
|
|
||
| #- run: | | ||
| # make bootstrap | ||
| # make release | ||
|
|
||
| - name: Perform CodeQL Analysis | ||
| uses: github/codeql-action/analyze@v3 |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the issue, add an explicit permissions: block to the workflow to limit the GITHUB_TOKEN privileges. For CodeQL analysis workflows, it is standard to grant read-only access to repository contents (contents: read) and write access only to security-events (needed to upload CodeQL results). The best place to add this block is at the root level of the workflow (before jobs:), so it applies to all jobs unless overridden.
- Edit the file
.github/workflows/codeql.yml. - Insert a block like this before the
jobs:key:permissions: contents: read security-events: write
No other imports or definitions are necessary, as this is a configuration change.
| @@ -9,6 +9,9 @@ | ||
| schedule: | ||
| - cron: "0 19 * * 0" | ||
|
|
||
| permissions: | ||
| contents: read | ||
| security-events: write | ||
| jobs: | ||
| CodeQL-Build: | ||
| # CodeQL runs on ubuntu-latest and windows-latest |
| if (lastValue) { | ||
| if (Array.isArray(pointer[modifiedLevel])) { | ||
| if (join) { | ||
| pointer[modifiedLevel] = lastValue; |
Check warning
Code scanning / CodeQL
Prototype-polluting assignment Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To address this vulnerability, every property name assignment derived from untrusted input must be protected against common prototype-polluting keys: __proto__, constructor, and prototype. The specific fix is to prevent any such keys from being used as property names in the insertInObj recursive function. This can be done either by skipping assignments with those keys or by throwing an error.
Implementation steps:
- Edit
insertInObjin packages/itmat-cores/src/utils/query.ts. - Before any property assignment (
pointer[modifiedLevel] = ...), check ifmodifiedLevelis one of the dangerous names. If so, skip that iteration or throw an error, depending on desired behavior (usually, skip). - Optionally, define a helper function for this key check for clarity.
- No changes needed outside the shown code.
| @@ -343,6 +343,7 @@ | ||
|
|
||
| // recursively create object structures, return the last pointer | ||
| function insertInObj(obj, levels: string[], lastValue: unknown, join: boolean, subjectId: string, visitId: string) { | ||
| const dangerousKeys = ['__proto__', 'constructor', 'prototype']; | ||
| let pointer = obj; | ||
| for (let i = 0; i < levels.length; i++) { | ||
| let modifiedLevel = levels[i]; | ||
| @@ -351,6 +352,11 @@ | ||
| } else if (levels[i] === 'm_visitId') { | ||
| modifiedLevel = visitId; | ||
| } | ||
| // Prevent property pollution | ||
| if (dangerousKeys.includes(modifiedLevel)) { | ||
| // Skip dangerous key | ||
| return undefined; | ||
| } | ||
| if (i === levels.length - 1) { | ||
| if (lastValue) { | ||
| if (Array.isArray(pointer[modifiedLevel])) { |
| pointer[modifiedLevel].push(lastValue); | ||
| } | ||
| } else { | ||
| pointer[modifiedLevel] = lastValue; |
Check warning
Code scanning / CodeQL
Prototype-polluting assignment Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix this vulnerability, we need to ensure that dangerous property names are never used as keys when assigning properties to objects in the insertInObj function. The best approaches are:
- Preferred approach: Before assigning to
pointer[modifiedLevel], check thatmodifiedLevelis not"__proto__","constructor", or"prototype". If it matches, skip assignment or throw an error. - Alternative: Use a safer associative structure (such as
Mapobjects, or objects without prototypesObject.create(null)), but this may require more invasive changes for compatibility.
Given the code's existing usage of plain objects, the simplest non-breaking fix is to add a guard in insertInObj before any assignment to pointer[modifiedLevel] (lines 363, 370, and 371). This can be accomplished by adding a function to check for these dangerous property names, and skipping assignment for them.
Edits:
- Add a utility function (locally in the file, near
insertInObj) to check for dangerous keys. - In
insertInObj, before every assignment topointer[modifiedLevel](lines 363, 370, and 371), add a check: ifmodifiedLevelis dangerous, skip the assignment, optionally log or throw. - No external dependencies are needed.
- Edits are localized to
insertInObj.
| @@ -342,6 +342,12 @@ | ||
| } | ||
|
|
||
| // recursively create object structures, return the last pointer | ||
| // Helper to guard against prototype-polluting keys | ||
| function isDangerousKey(key: string): boolean { | ||
| return key === '__proto__' || key === 'constructor' || key === 'prototype'; | ||
| } | ||
|
|
||
| // recursively create object structures, return the last pointer | ||
| function insertInObj(obj, levels: string[], lastValue: unknown, join: boolean, subjectId: string, visitId: string) { | ||
| let pointer = obj; | ||
| for (let i = 0; i < levels.length; i++) { | ||
| @@ -351,6 +357,11 @@ | ||
| } else if (levels[i] === 'm_visitId') { | ||
| modifiedLevel = visitId; | ||
| } | ||
| // Guard against prototype pollution before assigning or accessing | ||
| if (isDangerousKey(modifiedLevel)) { | ||
| // Optionally log or throw error; here, just skip assignment/access | ||
| return undefined; | ||
| } | ||
| if (i === levels.length - 1) { | ||
| if (lastValue) { | ||
| if (Array.isArray(pointer[modifiedLevel])) { |
| break; | ||
| } | ||
| if (pointer[modifiedLevel] === undefined) { | ||
| pointer[modifiedLevel] = {}; |
Check warning
Code scanning / CodeQL
Prototype-polluting assignment Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The best fix is to prevent property names that could cause prototype pollution (such as __proto__, constructor, or prototype) from being used as keys in objects.
To do this, in the insertInObj function, add a restriction to skip or throw an error if any modifiedLevel is one of these dangerous names.
The check should be applied right after determining the value of modifiedLevel and before using it to access or assign properties on the object.
No changes are needed to function signatures, but the check should be consistently applied within the property assignment loop to fully mitigate prototype pollution.
| @@ -351,6 +351,14 @@ | ||
| } else if (levels[i] === 'm_visitId') { | ||
| modifiedLevel = visitId; | ||
| } | ||
| // Prevent prototype pollution | ||
| if ( | ||
| modifiedLevel === '__proto__' || | ||
| modifiedLevel === 'constructor' || | ||
| modifiedLevel === 'prototype' | ||
| ) { | ||
| throw new Error('Prototype pollution attempt: forbidden property name "' + modifiedLevel + '"'); | ||
| } | ||
| if (i === levels.length - 1) { | ||
| if (lastValue) { | ||
| if (Array.isArray(pointer[modifiedLevel])) { |
| initializeProxyCacheCleanup(); | ||
| } else { | ||
| // Update the lastUsed timestamp | ||
| proxyCache[instance_id].lastUsed = Date.now(); |
Check warning
Code scanning / CodeQL
Prototype-polluting assignment Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The best way to fix this problem is to prevent user-controlled keys from polluting object prototypes. There are two main approaches:
- Use a Map object for
proxyCache. The ES6Mapstructure does not have special prototype properties, and keys are safe regardless of their string value—so settingMap.set('__proto__', ...)will not impact prototypes. - Sanitize input to prevent prototype-related keys from being used. By checking if
instance_idis'__proto__','constructor', or'prototype', and rejecting or handling such requests, you can avoid prototype pollution.
The single best solution is to switch proxyCache from an object to an ES6 Map, and adjust property access to use Map methods (get, set, etc.). This fixes the root cause and avoids the need for sanitization. All object lookups and assignments to proxyCache need to be switched to Map method calls (like .get(), .set(), .has()). Any for-in/object enumeration should also be updated as needed.
Required changes:
- Update the definition of
proxyCache. - Replace all uses of
proxyCache[instance_id]withproxyCache.get(instance_id)orproxyCache.set(instance_id, value)(including the assignment on line 558). - Ensure the proxy cache cleanup logic is compatible with
Map. - No new dependencies are required.
| @@ -11,8 +11,8 @@ | ||
|
|
||
| // const textDecoder = new TextDecoder('utf-8'); | ||
|
|
||
| export const proxyCache: Map<string, { proxy: httpProxy, lastUsed: number }> = new Map(); | ||
| export const registerContainSocketServer = (server: WebSocketServer, lxdManager: LxdManager) => { | ||
|
|
||
| server.on('connection', (clientSocket, req) => { | ||
| clientSocket.pause(); | ||
| let containerSocket: WebSocket | undefined; | ||
| @@ -488,7 +487,7 @@ | ||
|
|
||
| try { | ||
| // Retrieve the instance-specific target if not already cached | ||
| if (!proxyCache[instance_id]) { | ||
| if (!proxyCache.has(instance_id)) { | ||
| const { ip, port } = await getInstanceTarget(instance_id, instanceCore, req.user?.id); | ||
| if (!ip) { | ||
| throw new Error(`Could not determine IP for instance ${instance_id}`); | ||
| @@ -555,11 +554,19 @@ | ||
| initializeProxyCacheCleanup(); | ||
| } else { | ||
| // Update the lastUsed timestamp | ||
| proxyCache[instance_id].lastUsed = Date.now(); | ||
| const proxyEntry = proxyCache.get(instance_id); | ||
| if (proxyEntry) { | ||
| proxyEntry.lastUsed = Date.now(); | ||
| } | ||
| } | ||
|
|
||
| // Handle the request | ||
| proxyCache[instance_id].proxy.web(req, res); | ||
| const proxyEntry = proxyCache.get(instance_id); | ||
| if (proxyEntry) { | ||
| proxyEntry.proxy.web(req, res); | ||
| } else { | ||
| throw new Error('Proxy entry not found'); | ||
| } | ||
| return; // Add explicit return for consistency with vncProxyMiddleware | ||
| } catch (error) { | ||
| Logger.error(`Jupyter proxy error: ${JSON.stringify(error)}`); |
| initializeProxyCacheCleanup(); | ||
| } else { | ||
| // Update timestamp on use | ||
| vncProxyCache[instance_id].lastUsed = Date.now(); |
Check warning
Code scanning / CodeQL
Prototype-polluting assignment Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The best and safest way to fix this issue is to use a Map object instead of a plain JavaScript object for vncProxyCache. Map is resilient to arbitrary property names, including those that conflict with built-in object properties like __proto__, constructor, or prototype.
This change will require:
- Updating the definition and initialization of
vncProxyCachefrom an object literal{}tonew Map(). - Replacing all property access and assignment patterns, e.g.,
vncProxyCache[instance_id], with the appropriateMapmethods:get(instance_id),set(instance_id, value), and so forth.
All code interacting with vncProxyCache must be updated accordingly, but only the relevant shown code region in packages/itmat-interface/src/lxd/index.ts (bounded by snippet) can be edited.
No new external dependency is required, as Map is part of standard JavaScript.
| @@ -13,6 +13,8 @@ | ||
|
|
||
| export const registerContainSocketServer = (server: WebSocketServer, lxdManager: LxdManager) => { | ||
|
|
||
| // Use Map to avoid prototype pollution in vncProxyCache: | ||
| const vncProxyCache: Map<string, { proxy: any; lastUsed: number }> = new Map(); | ||
| server.on('connection', (clientSocket, req) => { | ||
| clientSocket.pause(); | ||
| let containerSocket: WebSocket | undefined; | ||
| @@ -600,7 +602,7 @@ | ||
|
|
||
| try { | ||
| // Get or create proxy instance | ||
| if (!vncProxyCache[instance_id]) { | ||
| if (!vncProxyCache.has(instance_id)) { | ||
| const { ip, port } = await getInstanceTarget(instance_id, instanceCore, req.user?.id); | ||
| if (!ip) { | ||
| throw new Error(`Could not determine IP for instance ${instance_id}`); | ||
| @@ -664,11 +666,11 @@ | ||
| initializeProxyCacheCleanup(); | ||
| } else { | ||
| // Update timestamp on use | ||
| vncProxyCache[instance_id].lastUsed = Date.now(); | ||
| vncProxyCache.get(instance_id)!.lastUsed = Date.now(); | ||
| } | ||
|
|
||
| // Handle the request | ||
| vncProxyCache[instance_id].proxy.web(req, res); | ||
| vncProxyCache.get(instance_id)!.proxy.web(req, res); | ||
| return; | ||
| } catch (error) { | ||
| Logger.error(`VNC proxy error: ${error}`); |
* refactor: Remove graphql usage from frontend * refactor: Remove graphql from backend * refactor: Revert back the ci file * refactor: Revert back the ci file
| status: enumEventStatus.FAIL, | ||
| errors: e instanceof Error ? e.message : 'Unknown error' | ||
| }); | ||
| res.status(500).json(e); |
Check warning
Code scanning / CodeQL
Information exposure through a stack trace Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
The best fix is to avoid exposing the error object (e) directly to the end user in the HTTP response, as this may include sensitive information such as stack traces or internal server errors. Instead, the catch block should:
- Return a generic error message to the client, such as "Internal server error" or "An unexpected error occurred".
- Log the detailed error information (
e, including stack traces if present) to the server log, which is already being done via thelog_collection.insertOne.
To implement this:
- In the catch block, replace
res.status(500).json(e);withres.status(500).json({ error: 'An unexpected error occurred' });, or a similarly generic message. - No changes to imports are required.
- No other code needs to be changed.
| @@ -148,7 +148,7 @@ | ||
| status: enumEventStatus.FAIL, | ||
| errors: e instanceof Error ? e.message : 'Unknown error' | ||
| }); | ||
| res.status(500).json(e); | ||
| res.status(500).json({ error: 'An unexpected error occurred' }); | ||
| return; | ||
| } | ||
| })().catch(() => { return; }); |
* refactor: Remove graphql usage from frontend * refactor: Remove graphql from backend * refactor: Revert back the ci file * refactor: Revert back the ci file * fix: Fix the UI issue of continueously rerendering
* refactor: Remove graphql usage from frontend * refactor: Remove graphql from backend * refactor: Revert back the ci file * refactor: Revert back the ci file * fix: Fix the UI issue of continueously rerendering * fix: Fix missing rate limiter for AE connection
No description provided.