Repository navigation
store: honor snap confinement on install - #133
Conversation
Deploying capos with
|
| Latest commit: |
3775c1b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://dd6df613.capos.pages.dev |
| Branch Preview URL: | https://fix-snap-install-confinement.capos.pages.dev |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
capos-snap | fa663b3 | Aug 20 2026, 07:58 AM |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3a733b4f2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11d006e561
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa663b323f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const channelMap = Array.isArray(payload['channel-map']) ? payload['channel-map'] : []; | ||
| const preferred = channelMap.find((entry:any) => entry.channel?.architecture === 'amd64' && entry.channel?.risk === 'stable') || channelMap[0] || {}; | ||
| const confinementByArchitecture = Object.fromEntries(channelMap | ||
| .filter((entry:any) => entry.channel?.name === 'stable' && ['strict','classic','devmode'].includes(entry.confinement)) |
There was a problem hiding this comment.
Match Canonical's full stable channel name
Canonical's v2 info response identifies stable channels with full names such as latest/stable (and risk: "stable"), rather than name: "stable", so this filter normally produces an empty confinement map. Because {} passes the UI's metadata-loaded check, copied commands then fall back to the amd64 app.confinement and can still use the wrong flag on another architecture. Fresh evidence against the resolved thread is that the new test fixture shortens these names to stable, masking the production response shape; select the default track's stable entry and reject an empty map instead.
Useful? React with 👍 / 👎.
| function validSnapName(name){return typeof name==="string"&&name.length<=64&&/^(?=.*[a-z])[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(name);} | ||
| async function installFromStore(name,channel){if(!state.session?.is_sudo)throw new Error("安装 Snap 需要 sudo 权限");if(state.installed.some(s=>s.name===name)){postStoreState();return}if(state.installing.has(name))return;state.installing.set(name,1);postStore({type:"capos-webdesktop:progress",version:1,name,progress:1});try{const body=new URLSearchParams({channel:channel||"stable"}).toString();await snapAction(name,"install",`安装 ${name}`,body,progress=>{state.installing.set(name,progress);postStore({type:"capos-webdesktop:progress",version:1,name,progress});});state.installing.delete(name);postStoreState();}catch(error){state.installing.delete(name);postStoreState();const message=error instanceof Error?error.message:String(error);postStore({type:"capos-webdesktop:error",version:1,name,message});toast(message,true);}} | ||
| function installConfinement(value){return value==="classic"||value==="devmode"||value==="strict"?value:"";} | ||
| async function storeConfinement(name,channel){const data=await request(`/snapd/find?name=${encodeURIComponent(name)}`);const snaps=Array.isArray(snapResult(data))?snapResult(data):[];const snap=snaps.find(item=>item?.name===name);if(!snap)throw new Error(`无法解析 ${name} 的安装元数据`);const requested=channel||"stable";const channels=snap.channels&&typeof snap.channels==="object"?Object.entries(snap.channels):[];const match=channels.find(([key,info])=>key===requested||key.endsWith(`/${requested}`)||info?.channel===requested);const mode=installConfinement(match?.[1]?.confinement||snap.confinement);if(!mode)throw new Error(`无法确定 ${name} 的 confinement`);return mode;} |
There was a problem hiding this comment.
Resolve the exact track before choosing confinement
When a snap exposes multiple tracks with a channel at the requested risk, a bare request such as stable makes this suffix match select whichever */stable entry happens to appear first, while the subsequent install still sends the bare channel for snapd to resolve against its default track. If those tracks use different confinement modes, WebDesktop supplies the flag for one track while installing another and the operation fails. Fresh evidence beyond the resolved architecture report is this newly added ambiguous multi-track lookup; resolve the default track first or require an exact full-channel match.
Useful? React with 👍 / 👎.
Summary
--classic/--devmodeinstall commands when requiredTests
npm run buildnpm run test:workernode --check package/capos/capos-webdesktop/htdocs/assets/app.jspackage/capos/capos-webdesktop/src/api.cpp