Skip to content

release: v1.4.3 - #9867

Open
sriramveeraghanta wants to merge 17 commits into
masterfrom
release/v1.4.3
Open

sriramveeraghanta wants to merge 17 commits into
masterfrom
release/v1.4.3

Conversation

@sriramveeraghanta

Copy link
Copy Markdown
Member

Summary

v1.4.3 patch release, cut from master (v1.4.2). It contains cherry-picked security fixes, dependency and container CVE fixes, and a few low-risk bug fixes from preview. The propel, i18n, refactor, perf and CI changes are left out.

Security fixes

Dependency and container CVE fixes

Infra

Bug fixes

Version

  • All package versions bumped to 1.4.3.

Testing

  • pnpm install --frozen-lockfile, pnpm check:types (28/28), and builds for web, space, admin and live all pass.
  • Backend (Docker test stack): all 96 tests added by the cherry-picked commits pass.
  • Full backend suite: 579 passed, 3 failed. The 3 failures are in test_projects_lite.py (429 from the API-key throttle) and depend on test order: the file passes on its own, and preview fails the same way. The throttle cache isn't reset between API-key contract test modules. This is a test-isolation problem, not a product regression. Follow-up on preview.
  • Docker images were not built locally. Please check the image CI build, especially the adapted nginx Dockerfiles and the proxy Caddy/Go module rebuild.

mguptahub and others added 17 commits September 23, 2026 02:19
…up endpoints (#9335)

* fix: add rate limiting to email/password sign-in and sign-up endpoints

All four password authentication views (app sign-in, app sign-up, space
sign-in, space sign-up) extended django.views.View, so DRF's global
AnonRateThrottle never ran and the endpoints accepted unlimited credential
guesses with no friction (brute-force / credential stuffing, GHSA-349j).

Add authentication_throttle_allows(request) at the top of each post()
method — before any DB access — using the same AuthenticationThrottle
already guarding the magic-code views. On rejection the view redirects with
RATE_LIMIT_EXCEEDED, consistent with all other throttled auth endpoints.
Default limit remains 10/minute, overridable via AUTHENTICATION_RATE_LIMIT.

Co-authored-by: Plane AI <noreply@plane.so>

* refactor: consolidate auth throttle into a decorator + add tests

- Extract the repeated throttle-and-redirect block from the six redirect-flow
  auth views (email + magic, app + space) into a single throttle_auth_redirect
  decorator in rate_limit.py. Behaviour is unchanged: the throttle still runs
  before any DB access; brute-force traffic is rejected without a DB hit.
- Add regression tests for the password sign-in/sign-up throttle on both app
  and space endpoints, mirroring the existing magic-code throttle tests.
- Reset the shared AuthenticationThrottle bucket before every test in
  test_authentication.py. All auth endpoints share one per-IP throttle scope,
  so the newly-throttled password requests exhausted the budget mid-file and
  caused unrelated tests to trip RATE_LIMIT_EXCEEDED.

---------

Co-authored-by: Plane AI <noreply@plane.so>
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
(cherry picked from commit e30605d)
* [WEB-8103] fix: stop leaking webhook HMAC secret_key on reads (GHSA-83rj)

WebhookEndpoint list/retrieve/patch pass a fields= allowlist that excludes
secret_key, but DynamicBaseSerializer.__init__ discards the caller
allowlist (fields = self.expand). With WebhookSerializer using
fields="__all__" and secret_key only in read_only_fields (read-only is
still serialized), the HMAC signing secret leaked on every webhook read
(GHSA-83rj-4282-x39v; admin-only).

Rather than secret_key = CharField(write_only=True) — which would let a
client inject their own secret on create/patch and break the intended
one-time reveal — hide it by default and reveal only where intended:

- WebhookSerializer.to_representation drops secret_key unless the
  show_secret_key context flag is set (secure by default). secret_key
  stays server-generated (default=generate_token) and non-writable.
- POST create and WebhookSecretRegenerateEndpoint pass show_secret_key so
  the secret is still returned once for the caller to configure their
  receiver; list/retrieve/patch no longer emit it.

Add contract regression tests (fail-before verified). Follow-up: the
DynamicBaseSerializer.__init__ allowlist bug affects other serializers —
tracked separately.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8103] test: address review — patch network boundary + pin to_representation

Per review (@sriramveeraghanta):
- Patch the network boundary (validate_url) instead of the whole private
  _validate_webhook_url method, so the domain/schema checks still run and
  the test survives a rename of the private method.
- Add an assertion that an explicit fields=("secret_key",) request still
  hides the key, pinning to_representation as the enforcement point so a
  future DynamicBaseSerializer._filter_fields fix can't silently re-open
  the leak.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8103] docs: spell out both levels of the dead fields= allowlist

The previous comment named only DynamicBaseSerializer.__init__ discarding the
caller's fields=, which is half the root cause. _filter_fields never removes
anything either: it builds `allowed` purely to attach expansion serializers for
names not already on the serializer, then returns self.fields unfiltered
(serializers/base.py:45-119).

So the fields= kwargs in views/webhook/base.py are no-ops on two independent
levels. Documented so a future `fields = fields or self.expand` fix isn't
assumed to re-activate the allowlists for confidentiality — _filter_fields has
to be made restrictive first. The show_secret_key context flag remains the sole
enforcement point.

Addresses @sriramveeraghanta's review on #9382. 6/6 contract tests pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3052792)
* [WEB-8110] fix: sanitize page list order_by against an allowlist (GHSA-2v48)

PageViewSet.get_queryset passed the raw order_by query param into
.order_by(). In Django 4.2 .order_by() resolves field names at call time,
so an unknown field (e.g. order_by=password) raises FieldError → 500 DoS,
and a valid relation path (e.g. order_by=owned_by__password) enables ORM
relational traversal (GHSA-2v48-qcjw-74ch).

Add PAGE_ORDER_BY_ALLOWLIST to utils/order_queryset.py and wrap the param
with the existing sanitize_order_by() before it reaches .order_by(),
matching the issue/project/view/notification endpoints. Unknown or
malformed values fall back to the safe -created_at default.

Covers only the app project-pages residual; the 3 external-REST-API sites
in the advisory are handled by PR #9348. EE Wiki counterpart: WEB-8111.

Add contract regression tests (fail-before verified).

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8110] fix: fold sanitized order_by into a single order_by() call (review)

Address CodeRabbit + Copilot on #9387: the sanitized .order_by(user) was
immediately overridden by a later .order_by("-is_favorite", "-created_at"),
so the order_by param had no effect on the result (dead code) and cost an
extra query-build step.

Merge them into one .order_by("-is_favorite", <sanitized>, "id") — matching
the EE project-pages viewset — so favourites stay pinned first, the
allowlisted user ordering actually applies as the secondary sort, and id is
a stable pagination tiebreak. The no-param default is unchanged
(-created_at). Add a test asserting order_by=name / -name actually reorders
the results.

Co-authored-by: Plane AI <noreply@plane.so>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
(cherry picked from commit d25b99c)
…9442)

* [WEB-8283] fix: bind Spaces board object IDs to the anchor's project

The public Spaces board endpoints resolved the DeployBoard from the URL
anchor but trusted the caller-supplied issue_id/comment_id/intake_id
verbatim, without verifying the object belonged to that board's
project/workspace. Any authenticated user could write comments,
reactions and votes onto arbitrary issues cross-tenant, and read EXTERNAL
comments from a different project in the same workspace.

Bind every caller-supplied object id to the board's project + workspace
before writing:
- comment / issue-reaction / vote create: require the issue to exist in
  the board's project via Issue.issue_objects (excludes draft/archived/
  triage), else 404.
- comment-reaction create: require the comment to exist in the board's
  project with access="EXTERNAL", else 404.
- intake create: require the URL intake_id to match the board's intake,
  else 400.
- comment list read: scope the queryset to the board's project_id.

Also add the missing is_votes_enabled gate on vote create for parity with
comment/reaction create (pre-existing gap in the same method).

Adds contract regression tests (fail-before verified): cross-tenant
writes and the cross-project comment read now rejected, with positive
controls confirming legitimate board writes/reads still succeed.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8283] test: address Copilot review — cross-workspace + votes-disabled coverage

- Add cross-workspace write test (issue in a different workspace) to
  exercise the workspace_id binding, matching the advisory's cross-tenant
  impact (previously only same-workspace/different-project was covered).
- Add a regression test for the new is_votes_enabled gate on vote create
  (votes-disabled board → 400), preventing the pre-existing gap from
  reappearing.
- Clarify the section header comment: cross-tenant writes return 404 for
  issue/comment binding, 400 for the intake binding mismatch.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8283] refactor: extract board-scope guards into shared helpers

Address CodeRabbit review: the identical "object belongs to the board's
project+workspace" existence check was duplicated across four create()
methods (in four different ViewSets). Extract two module-level helpers —
_issue_in_board_scope and _comment_in_board_scope — so the check is a
single source of truth and cannot drift between endpoints or be forgotten
on a new one (the exact class of bug this PR fixes).

Behavior-preserving; 14 contract tests still green.

Co-authored-by: Plane AI <noreply@plane.so>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

* fix(security): use the deploy board's project_id in the reaction-create activity log

CommentReactionPublicViewSet.create() logged the activity with
str(self.kwargs.get("project_id", None)) — this route's URL only ever
supplies anchor and comment_id, never project_id, so every comment
reaction created on a public board logged project_id="None", silently
corrupting the activity/audit trail. destroy() on the same viewset
already resolves the correct project_id from the deploy board; create()
now does the same.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8283] fix: apply board-scope guards to comment/reaction read, update and delete paths

The board/issue/external-comment scoping added by this PR's create() methods
was never applied to the list, update and delete paths built on the same
models. A caller could read reactions on an INTERNAL (non-public) comment
through the public reaction list, or reach a comment or reaction they
authored through a board it doesn't actually belong to via partial_update()
or destroy(), since those methods looked up objects by pk/actor only.

Bind IssueCommentPublicViewSet.partial_update()/destroy() to the board's
project, workspace, issue_id and EXTERNAL access; bind
IssueReactionPublicViewSet.destroy() to the board's project (previously only
workspace-scoped); and bind CommentReactionPublicViewSet.get_queryset()/
destroy() to EXTERNAL comments only. Add regression coverage for each gap,
plus positive controls confirming legitimate reads/writes on the board's own
objects still work.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
(cherry picked from commit 5b5af0a)
…9466)

* [WEB-8352] fix(security): scope SubIssuesEndpoint to the URL project (GHSA-gxhv-fw9x-2pg3)

SubIssuesEndpoint is guarded only by ProjectEntityPermission, which verifies
the caller belongs to the URL project_id but not that the path issue_id lives
in that project. Both handlers then resolved issues without a project scope:

- GET filtered sub-issues by parent_id + workspace__slug only, leaking the
  names/priorities/assignees/dates of another project's sub-issues (read IDOR).
- POST loaded the parent by bare pk (no workspace/project scope) and filtered
  the moved sub-issues by workspace__slug only, letting any project member
  re-parent issues from other projects/workspaces (write IDOR).

Scope the parent lookup and both sub-issue querysets to the URL project_id
(and bind the parent to the workspace), returning 404 when the parent is not
in the caller's project. Adds 5 contract tests (3 security, 2 positive
controls); fail-before verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [WEB-8352] fix: dispatch sub-issue activity only for project-scoped issues (CodeRabbit/Copilot #9466)

The DB update + response were scoped to the URL project, but the activity loop
still iterated the raw caller-supplied sub_issue_ids. A cross-project id
(excluded from the re-parent) would still fire issue_activity.delay, whose task
does an unscoped Issue.objects.get and bumps updated_at — touching a foreign
issue and creating a bogus activity row.

Dispatch from the project-scoped sub_issues (scoped_sub_issue_ids) instead.
Strengthened the test to assert the foreign issue is absent from the response
body (sub_issues / state_distribution) and that no activity is dispatched for it
(mock). Fail-before verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Plane AI <noreply@plane.so>
(cherry picked from commit 3478d4f)
…ently dropping invalid ids (#9526)

Work item create/update via the external API returned 200/201 even
when assignees or labels didn't belong to the project, quietly
filtering the invalid ids out with no error. Now raises the same kind
of ValidationError already used for state/parent, matching the pattern
of #9517.

(cherry picked from commit aacfaac)
#9763)

* fix(api): avoid re-crawling issue link on update when url is unchanged

* fix(api): avoid recrawling unchanged issue links

(cherry picked from commit 1fec307)
… removed Docker Hub org (#9829)

MinIO removed the `minio` organisation from Docker Hub. Every deployment
that pulls `minio/minio` or `minio/mc` now fails with:

    pull access denied for minio/minio, repository does not exist
    or may require 'docker login'

The registry returns 401 (not 404) to anonymous clients, so the error
reads like a credentials problem when the repository is simply gone.

quay.io is MinIO's own second registry and still serves both images
publicly (multi-arch: amd64, arm64, ppc64le). Repoint every default at
quay.io, and pin an explicit RELEASE tag instead of `:latest` so a
future upstream change to a floating tag cannot break deployments the
same way:

  minio -> quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z
  mc    -> quay.io/minio/mc:RELEASE.2025-08-13T08-35-41Z

These are the digests `:latest` currently resolves to on quay.

Note: the community MinIO build is effectively frozen upstream (last
community push was 2025-09-07), so this unblocks deployments but does
not change the longer-term need to steer self-hosted users toward
external S3, with bundled MinIO as a dev/eval convenience.

Claude-Session: https://claude.ai/code/session_01TB2aRDJ5BMx6m5c7jDzkqM

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit f25814c)
…9443)

* [WEB-8289] fix: scope draft-to-issue conversion to the draft owner (GHSA-vfqm-7rh7-84hq)

WorkspaceDraftIssueViewSet.create_draft_to_issue resolved the draft with
get_queryset().filter(pk=draft_id) — scoped only to the workspace, no
created_by check — while the decorator admits any workspace ADMIN/MEMBER.
Drafts are private to their creator, so any member could pass another
user's draft_id to convert that draft into an issue, reassign (steal) its
file assets, and delete the victim's draft.

Scope the lookup to created_by=request.user (mirroring retrieve /
partial_update) and 404 when no owned draft matches. The explicit null
guard also removes a latent AttributeError on the following .project_id
access when the draft is not found.

Adds contract regression tests (fail-before verified): a non-owner
member is rejected with 404 and the draft + its assets are left intact,
with a positive control confirming the owner can still convert.

Co-authored-by: Plane AI <noreply@plane.so>

* [WEB-8289] test: make fixture ownership real (address Copilot review)

Project and FileAsset fixtures passed created_by=create_user to
objects.create(), but BaseModel.save() nulls created_by when there is no
current request user (tests), so the ownership claim was silently a
no-op. Instantiate + save(created_by_id=...) instead — same pattern
already used for the draft — so the fixtures are accurate.

Co-authored-by: Plane AI <noreply@plane.so>

* chore(security): drop advisory identifiers from code comments

Explanations kept unchanged; only the IDs are removed.

Co-authored-by: Plane AI <noreply@plane.so>

---------

Co-authored-by: Plane AI <noreply@plane.so>
(cherry picked from commit a896115)
…invited project (#9866)

`ProjectJoinEndpoint.post` looked up the accepting user's existing
`ProjectMember` row by `(workspace_id, member)` and omitted `project_id`.
Accepting an invitation to project Y therefore reactivated whatever membership
row the user already had in the workspace -- typically a project they had been
removed from -- while project Y itself never received a membership row at all.

A companion no-op, `project_member.role = project_member.role`, left the stale
row at its original role, so a user removed as ADMIN from another project came
back as ADMIN even though the new invite was for a GUEST.

Scope the lookup to `project_id` and apply `project_invite.role` on reactivation.
The correct, project-scoped pattern already existed in
`UserProjectInvitationsViewset.create` in the same file.

Adds three regression tests covering: the invited project receives the
membership, an unrelated membership is not reactivated, and a rejoin applies the
invitation's role rather than the stale one.

(cherry picked from commit bae037c)
…9734)

* chore: upgrade pnpm to 11.10, turbo to 2.10.11, patch postcss-selector-parser

- packageManager: pnpm@11.3.0 -> pnpm@11.10.0
- turbo catalog: 2.9.18 -> 2.10.11 (latest)
- override postcss-selector-parser >=7.1.0 <7.1.3 to 7.1.3 (dependabot
  alert #345, DoS via uncontrolled AST recursion)

* chore: remove comment from postcss-selector-parser override

(cherry picked from commit 3717500)
Bumps the npm_and_yarn group with 1 update in the / directory: [sanitize-html](https://github.com/apostrophecms/apostrophe/tree/HEAD/packages/sanitize-html).

Updates `sanitize-html` from 2.17.5 to 2.17.7
- [Changelog](https://github.com/apostrophecms/apostrophe/blob/main/packages/sanitize-html/CHANGELOG.md)
- [Commits](https://github.com/apostrophecms/apostrophe/commits/HEAD/packages/sanitize-html)

---
updated-dependencies:
- dependency-name: sanitize-html
  dependency-version: 2.17.7
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit cb28b70)
(cherry picked from commit 97ea97e, adapted: web/admin keep nginx on this branch, so only the APK security-upgrade layer is applied there)
* fix(security): clear the 2026-09-10 nightly Trivy findings

Two advisories published 2026-09-08 21:2x UTC reached Trivy's DB between
the 09-09 nightly (green on every plane-* leg) and the 09-10 one, turning
plane-live-community and plane-space-community red on unchanged images.

- js-yaml 4.3.1 -> 4.3.2 (CVE-2026-84375). The exact pin was the patched
  version at the time and became the vulnerable one; the comment now says to
  bump rather than widen it, since a range drifts onto the 5.x break.
- sharp ^0.35.3 -> ^0.35.4 (GHSA-rgj7-g3m4-5g8c, libheif GHSA-g89c-p67h-r497
  and GHSA-2jg2-4ch7-h545).

The third finding on plane-proxy/admin/frontend-community, CVE-2026-84445 in
the Caddy binary's grpc-go, needs no change here: 2.11.4 is the newest Caddy
published, and the nightly scan reads plane-ee's .trivyignore.yaml for every
leg, where it is suppressed at **/bin/caddy on the reachability argument that
Caddy runs no gRPC xDS server.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: drop the added comment from pnpm-workspace.yaml

Review feedback from @sriramveeraghanta. The diff is now two version changes and
nothing else; the advisory ids and the reasoning stay in the PR description.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 2f895b8)
- vitest / @vitest/mocker: bump catalog to ^4.1.11 (path traversal /
  arbitrary file read via redirect mock)
- qs: pin override to 6.16.0 (DoS via attacker-controlled isBuffer,
  array-limit bypass via bracket-key comma parsing)
- morgan: pin override to 1.12.0 (log forging via unescaped Unicode
  line separators)
- postcss-selector-parser: pin the 6.1.x line to 6.1.3 (DoS via
  uncontrolled AST recursion); existing override only covered 7.x
- djangorestframework: 3.17.1 -> 3.17.2 (DATA_UPLOAD_MAX_MEMORY_SIZE
  bypass, AdminRenderer data disclosure)

@tiptap/core is intentionally left on v2: the advisory is only patched
in 3.30.4, a breaking major upgrade that needs a dedicated migration.

(cherry picked from commit a0efb67)
Copilot AI lite review requested due to automatic review settings September 22, 2026 21:01
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 3daec65e-d3c8-4558-a3be-9de10f8426c3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Critical API intake validation and AIO image hardening issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 High severity · 4 Medium severity

Open (6)
What changed in this PR

Plane v1.4.3 is a patch release containing security fixes, dependency and container CVE updates, infrastructure changes, and targeted backend bug fixes.

Changes:

  • Updated dependencies, package versions, lockfiles, Docker images, and MinIO sources.
  • Added authentication throttling, access scoping, secret redaction, ordering safeguards, and validation.
  • Added regression and contract test coverage.
File Summary
pnpm-workspace.yaml Dependency catalog and security override updates.
packages/​utils/​package.json Package version bump.
packages/​ui/​package.json Package version bump.
packages/​typescript-config/​package.json Package version bump.
packages/​types/​package.json Package version bump.
packages/​tailwind-config/​package.json Package version bump.
packages/​shared-state/​package.json Package version bump.
packages/​services/​package.json Package version bump.
packages/​propel/​package.json Package version bump.
packages/​logger/​package.json Package version bump.
packages/​i18n/​package.json Package version bump.
packages/​hooks/​package.json Package version bump.
packages/​editor/​package.json Package version bump.
packages/​constants/​package.json Package version bump.
packages/​codemods/​package.json Package version bump.
package.json Release version and pnpm update.
docker-compose.yml MinIO image pinned to Quay.
docker-compose-test.yml Test MinIO image pinned to Quay.
docker-compose-local.yml Local MinIO image pinned to Quay.
deployments/​cli/​community/​docker-compose.yml Community MinIO image pinned to Quay.
deployments/​aio/​community/​supervisor.conf Removes the runtime npx dependency.
deployments/​aio/​community/​Dockerfile AIO image hardening; critical (1 vote) finding that copying /usr/lib after upgrades can replace fixed libraries.
apps/​web/​package.json Application version bump.
apps/​web/​Dockerfile.web Alpine hardening; moderate (2 votes) finding that the explicit Turbo pin remains at 2.9.18.
apps/​space/​package.json Application version bump.
apps/​space/​Dockerfile.space Runtime hardening; moderate (2 votes) finding that the explicit Turbo pin remains at 2.9.18.
apps/​proxy/​Dockerfile.ce Caddy and Go dependency updates.
apps/​live/​package.json Application version bump.
apps/​live/​Dockerfile.live Runtime hardening; moderate (2 votes) finding that the explicit Turbo pin remains at 2.9.18.
apps/​api/​tests/​RUNNING_TESTS.md Test-stack documentation updates.
apps/​api/​requirements/​base.txt Django REST Framework security update.
apps/​api/​plane/​utils/​order_queryset.py Page ordering allowlist.
apps/​api/​plane/​tests/​unit/​views/​test_issue_link.py Conditional issue-link crawling tests.
apps/​api/​plane/​tests/​unit/​serializers/​test_issue_serializer_api.py Assignee and label validation tests.
apps/​api/​plane/​tests/​contract/​app/​test_webhook_secret_key_scope_app.py Webhook secret visibility tests.
apps/​api/​plane/​tests/​contract/​app/​test_sub_issue_cross_project_scope_app.py Sub-issue project-scoping tests.
apps/​api/​plane/​tests/​contract/​app/​test_spaces_board_object_scope_app.py Spaces board object-scoping tests.
apps/​api/​plane/​tests/​contract/​app/​test_project_join_cross_project_activation.py Project invitation activation tests.
apps/​api/​plane/​tests/​contract/​app/​test_page_order_by_allowlist_app.py Safe page-ordering tests.
apps/​api/​plane/​tests/​contract/​app/​test_draft_to_issue_owner_scope_app.py Draft ownership enforcement tests.
apps/​api/​plane/​tests/​contract/​app/​test_authentication.py Authentication throttling tests; moderate (1 vote) finding regarding clearing the entire shared cache.
apps/​api/​plane/​tests/​contract/​api/​test_issue_assignee_label_validation.py Assignment validation tests; moderate (1 vote) finding that both Celery settings must be restored.
apps/​api/​plane/​space/​views/​issue.py Scopes public issue, comment, reaction, and vote access.
apps/​api/​plane/​space/​views/​intake.py Binds intake submissions to boards.
apps/​api/​plane/​authentication/​views/​space/​magic.py Space magic-link throttling.
apps/​api/​plane/​authentication/​views/​space/​email.py Space password throttling.
apps/​api/​plane/​authentication/​views/​app/​magic.py App magic-link throttling.
apps/​api/​plane/​authentication/​views/​app/​email.py App password throttling.
apps/​api/​plane/​authentication/​rate_limit.py Redirect-flow throttle decorator.
apps/​api/​plane/​app/​views/​workspace/​draft.py Restricts draft conversion to owners.
apps/​api/​plane/​app/​views/​webhook/​base.py Enables controlled webhook secret disclosure.
apps/​api/​plane/​app/​views/​project/​invite.py Scopes membership activation and invite roles.
apps/​api/​plane/​app/​views/​page/​base.py Sanitizes page ordering.
apps/​api/​plane/​app/​views/​issue/​sub_issue.py Scopes sub-issue reads and writes.
apps/​api/​plane/​app/​views/​issue/​link.py Avoids unnecessary link recrawls.
apps/​api/​plane/​app/​views/​cycle/​archive.py Handles cycles without end dates.
apps/​api/​plane/​app/​serializers/​webhook.py Hides webhook secrets by default.
apps/​api/​plane/​api/​views/​issue.py Avoids unnecessary API link recrawls.
apps/​api/​plane/​api/​views/​cycle.py Handles cycles without end dates.
apps/​api/​plane/​api/​serializers/​issue.py Rejects invalid assignee and label IDs; critical (1 vote) finding that missing project context breaks valid API intake updates.
apps/​api/​package.json API version bump.
apps/​api/​Dockerfile.api Python and Alpine package updates.
apps/​admin/​package.json Application version bump.
apps/​admin/​Dockerfile.admin Alpine hardening; moderate (2 votes) finding that the explicit Turbo pin remains at 2.9.18.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +108 to +114
valid_assignee_ids = set(
ProjectMember.objects.filter(
project_id=self.context.get("project_id"),
is_active=True,
role__gte=15,
member_id__in=data["assignees"],
).values_list("member_id", flat=True)
# bump APK_SECURITY_PATCH to bust buildx's cached layer (keyed on this command
# string), otherwise a rebuild silently re-ships the old packages.
ARG APK_SECURITY_PATCH=2026-09-07
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available
Comment on lines +83 to +84
ARG APK_SECURITY_PATCH=2026-09-07
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available && rm -rf /var/cache/apk/*
Comment thread apps/live/Dockerfile.live
Comment on lines +60 to +61
ARG APK_SECURITY_PATCH=2026-09-07
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available
Comment on lines +86 to +87
ARG APK_SECURITY_PATCH=2026-09-07
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available
Comment thread apps/web/Dockerfile.web
Comment on lines +83 to +84
ARG APK_SECURITY_PATCH=2026-09-07
RUN echo "apk-security-patch ${APK_SECURITY_PATCH}" && apk update && apk upgrade --no-cache --available && rm -rf /var/cache/apk/*

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants