fix(studio): review round 1 (symlink-safe writes, remote allowlist, upload cap/types/no-overwrite, owner rule at publish/sync/resolve, studio/repos layout and read-only imports, side-effect-free list)
C1: writes lstat every path component and refuse symlinks (dangling included), check the parent's real path after mkdir, and open with O_NOFOLLOW. I1: only https://, ssh:// and git@host: remotes; protocol.file/ext/fd=never on every fetch and push; global/system git config ignored. I2: STC_UPLOAD_MAX_MB cap (default 100) by Content-Length and while streaming; extension allowlist (415); stcourse.yaml refused; 409 unless overwrite=true; sandboxing CSP on draft raw files. I3: owner-only visibility/source.kind rule checked on the merged result at publish and sync, and at resolve; publish also validates the merged tree. I4: bare repos in <dataDir>/studio/repos/<id>.git; imported courses read-only. I5: list status comes from the bare repo; drafts are created lazily. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
667f3e814b
commit
2d162a4282
12 files changed
+563
-76
No files matched your search
@@ -1,9 +1,9 @@
|
||||
// Server entry of @stc/feature-studio. The browser imports "@stc/feature-studio/web" instead (no server code).
|
||||
export { studioFeature, OUTSIDE_MESSAGE, type StudioFeature, type StudioFeatureOptions } from "./server/feature";
|
||||
export { studioFeature, OUTSIDE_MESSAGE, IMPORTED_MESSAGE, uploadMaxBytes, UPLOAD_EXTENSIONS, type StudioFeature, type StudioFeatureOptions } from "./server/feature";
|
||||
export { createDraftWriter, type DraftWriter, type DraftWriterOptions } from "./server/draft-writer";
|
||||
export { createStudioStore, contentHash, type StudioStore, type Identity, type DraftStatus, type PublishResult, type SyncResult } from "./server/store";
|
||||
export { createStudioStore, contentHash, isAllowedRemote, ownerRequiredFor, type StudioStore, type Identity, type DraftStatus, type PublishResult, type SyncResult } from "./server/store";
|
||||
export { createPublishedWatcher, type PublishedWatcher } from "./server/watch";
|
||||
export { studioCourseDirs, studioWorktreesDir } from "./server/paths";
|
||||
export { studioCourseDirs, studioWorktreesDir, studioReposDir } from "./server/paths";
|
||||
export { studioWeb } from "./web";
|
||||
|
||||
/** The studio adds no tables: authors use Phase 0's `course_authors`. */
|
||||
|
||||
Reference in new issue
Block a user