phala 0.0.1-alpha-16 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
@@ -108,8 +108,8 @@ Operation completed. Full log available at: ${y}`),a()):c(new Error(`Process exi
|
|
108
108
|
`).filter(a=>a&&!a.includes("<none>")).filter(a=>a.includes(`${n}/`)).map(a=>({imageName:a}))}catch(e){return o.error(`Failed to list local Docker images: ${e instanceof Error?e.message:String(e)}`),[]}}};import Pt from"prompts";var It=new Zr().name("login").description("Login to Docker Hub").option("-u, --username <username>","Docker Hub username").option("-p, --password <password>","Docker Hub password").option("-r, --registry <registry>","Docker registry URL").action(async t=>{try{let e=t.username,r=t.password,n=t.registry;if(!e){o.info("First we need your Docker Hub username to check if you are already logged in.");let l=await Pt({type:"text",name:"username",message:"Enter your Docker Hub username:",validate:y=>y.length>0?!0:"Username cannot be empty"});l.username||(o.error("Username is required"),process.exit(1)),e=l.username}let s=new T("",e,n);if(await s.login(e)){o.success(`${e} is logged in to Docker Hub`);return}if(!r){let l=await Pt({type:"password",name:"password",message:"Enter your Docker Hub password:",validate:y=>y.length>0?!0:"Password cannot be empty"});l.password||(o.error("Password is required"),process.exit(1)),r=l.password}await s.login(e,r,n)||(o.error("Failed to login to Docker Hub"),process.exit(1)),await tt({username:e,registry:n||null}),o.success("Logged in to Docker Hub successfully")}catch(e){o.error(`Failed to login to Docker Hub: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as Yr}from"commander";import Dt from"node:path";import At from"inquirer";import Jr from"node:fs";var Rt=new Yr().name("build").description("Build a Docker image").option("-i, --image <image>","Image name").option("-t, --tag <tag>","Image tag").option("-f, --file <file>","Path to Dockerfile","Dockerfile").action(async t=>{try{let e=await L();if(e||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1)),!t.image){let c=await At.prompt([{type:"input",name:"image",message:"Enter the Docker image name:",validate:l=>l.trim()?!0:"Image name is required"}]);t.image=c.image}if(!t.tag){let c=await At.prompt([{type:"input",name:"tag",message:"Enter the Docker image tag:",default:"latest",validate:l=>l.trim()?!0:"Tag is required"}]);t.tag=c.tag}let r=Dt.resolve(process.cwd(),t.file);Jr.existsSync(r)||(o.info(`Default Dockerfile not found at ${r}`),t.file=await B("Enter the path to your Dockerfile:","Dockerfile","file"));let n=Dt.resolve(process.cwd(),t.file);await new T(t.image,e.username,e.registry).buildImage(n,t.tag)||(o.error("Failed to build Docker image"),process.exit(1)),o.success(`Docker image ${e.username}/${t.image}:${t.tag} built successfully`)}catch(e){o.error(`Failed to build Docker image: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as Xr}from"commander";import Qr from"inquirer";var Ft=new Xr().name("push").description("Push a Docker image to Docker Hub").option("-i, --image <image>","Full image name (e.g. username/image:tag)").action(async t=>{try{let e=await L();e||(o.error('Docker information not found. Please login first with "phala docker login"'),process.exit(1));let r=t.image;if(!r){let a=await T.listLocalImages();if(a.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let c=Array.from(new Set(a.map(y=>y.imageName))),{selectedImage:l}=await Qr.prompt([{type:"list",name:"selectedImage",message:"Select an image to push:",choices:c}]);r=l}}await new T("",e.username,e.registry).pushImage(r)||(o.error("Failed to push Docker image"),process.exit(1)),o.success(`Docker image ${r} pushed successfully`)}catch(e){o.error(`Failed to push Docker image: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as eo}from"commander";import de from"inquirer";import ue from"node:fs";import _e from"node:path";var Mt=new eo().name("generate").description("Generate a Docker Compose file").option("-i, --image <imageName>","Docker image name to use in the compose file (e.g. phala/phala-cloud)").option("-e, --env-file <envFile>","Path to environment variables file").option("-o, --output <output>","Output path for generated docker-compose.yml").option("--template <template>","Template to use for the generated docker-compose.yml").action(async t=>{try{let e=await L();(!e||!e.username)&&(o.error("Docker Hub username not found. Please login first with `phala docker login`"),process.exit(1));let r=t.image;if(!r){let l=await T.listLocalImages();if(l.length===0&&(o.error('No local Docker images found. Please build an image first with "phala docker build"'),process.exit(1)),!r){let y=Array.from(new Set(l.map(k=>k.imageName))),{selectedImage:g}=await de.prompt([{type:"list",name:"selectedImage",message:"Select an image to use in the compose file:",choices:y}]);r=g}}let n=t.envFile;if(n)try{j(n)}catch{o.error(`File not found: ${n}`),process.exit(1)}else{let l=_e.join(process.cwd(),".env");if(ue.existsSync(l)){let{useDefault:g}=await de.prompt([{type:"confirm",name:"useDefault",message:"Use .env file in current directory?",default:!0}]);g&&(n=l)}if(!n){let{envPath:g}=await de.prompt([{type:"input",name:"envPath",message:"Enter path to environment variables file:",validate:k=>{try{return j(k),!0}catch{return`File not found: ${k}`}}}]);n=g}}let s=t.output;if(!s&&(s=_e.join(process.cwd(),"docker-compose.yml"),ue.existsSync(s))){let{confirmOverwrite:l}=await de.prompt([{type:"confirm",name:"confirmOverwrite",message:`File ${s} already exists. Overwrite?`,default:!1}]);if(!l){let{customPath:y}=await de.prompt([{type:"input",name:"customPath",message:"Enter alternative output path:",default:_e.join(process.cwd(),"docker-generated-compose.yml")}]);s=y}}let a=new T("",e.username,e.registry);n?o.info(`Generating Docker Compose file for ${r} using env file: ${n}`):o.info(`Generating Docker Compose file for ${r} without env file`);let c=await a.buildComposeFile(r,n,t.template);if(c!==s){let l=_e.dirname(s);ue.existsSync(l)||(o.info(`Creating directory: ${l}`),ue.mkdirSync(l,{recursive:!0})),ue.copyFileSync(c,s)}o.success(`Docker Compose file generated successfully: ${s}`)}catch(e){o.error(`Failed to generate Docker Compose file: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});var Vt=new to().name("docker").description("Login to Docker Hub and manage Docker images").addCommand(It).addCommand(Rt).addCommand(Ft).addCommand(Mt);import{Command as no}from"commander";import{Command as ro}from"commander";var Lt=new ro().name("start").description("Start the TEE simulator").option("-i, --image <image>","Simulator image",ot).option("-p, --port <port>","Simulator port (default: 8090)","8090").option("-t, --type <type>","Simulator type (docker, native)","docker").action(async t=>{try{if(t.type==="docker")await new T("").runSimulator(t.image,t.port)||(o.error("Failed to start TEE simulator"),process.exit(1));else if(t.type==="native")if(wt()||await St(),await Se()){o.success("TEE simulator is already running");return}else{let r=_t();o.success("TEE simulator started successfully")}else o.error("Invalid simulator type"),process.exit(1)}catch(e){o.error(`Failed to start TEE simulator: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as oo}from"commander";var Ot=new oo().name("stop").description("Stop the TEE simulator").option("-t, --type <type>","Simulator type (docker, native)","docker").action(async t=>{try{t.type==="docker"?await new T("").stopSimulator()||(o.error("Failed to stop TEE simulator"),process.exit(1)):t.type==="native"?await Et()||(o.error("Failed to stop TEE simulator"),process.exit(1)):(o.error("Invalid simulator type"),process.exit(1))}catch(e){o.error(`Failed to stop TEE simulator: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});var Ut=new no().name("simulator").description("TEE simulator commands").addCommand(Lt).addCommand(Ot);import{Command as _o}from"commander";import{Command as io}from"commander";import so from"inquirer";import{z as Nt}from"zod";async function Ee(){try{let t=await $.get(x.CVMS(0));return Nt.array(Le).parse(t)}catch(t){throw new Error(`Failed to get CVMs: ${t instanceof Error?t.message:String(t)}`)}}async function xe(t){let r=(await Ee()).find(n=>n.hosted?.app_id===t||`app_${n.hosted?.app_id}`===t);if(!r)o.error(`CVM with App ID app_${t} not detected`),process.exit(1);else return o.success(`CVM with App ID app_${t} detected`),r.hosted?.app_id||""}async function X(t){try{let e=await $.get(x.CVM_BY_APP_ID(t));return dt.parse(e)}catch(e){throw new Error(`Failed to get CVM by App ID: ${e instanceof Error?e.message:String(e)}`)}}async function zt(t){try{let e=await $.post(x.CVM_PUBKEY,t);return pt.parse(e)}catch(e){throw new Error(`Failed to get pubkey from CVM: ${e instanceof Error?e.message:String(e)}`)}}async function jt(t){try{let e=await $.post(x.CVM_FROM_CONFIGURATION,t);return ce.parse(e)}catch(e){throw e instanceof Nt.ZodError?(o.error("Schema validation error:",JSON.stringify(e.errors,null,2)),o.error("API response:",JSON.stringify(e.format(),null,2)),new Error(`Response validation failed: ${JSON.stringify(e.errors)}`)):new Error(`Failed to create CVM: ${e instanceof Error?e.message:String(e)}`)}}async function Bt(t){try{let e=await $.post(x.CVM_START(t));return ce.parse(e)}catch(e){throw new Error(`Failed to start CVM: ${e instanceof Error?e.message:String(e)}`)}}async function Wt(t){try{let e=await $.post(x.CVM_STOP(t));return ce.parse(e)}catch(e){throw new Error(`Failed to stop CVM: ${e instanceof Error?e.message:String(e)}`)}}async function Gt(t){try{let e=await $.post(x.CVM_RESTART(t));return ce.parse(e)}catch(e){throw new Error(`Failed to restart CVM: ${e instanceof Error?e.message:String(e)}`)}}async function Ht(t,e){try{let r=await $.put(x.CVM_UPGRADE(t),e);return ft.parse(r)}catch(r){throw new Error(`Failed to upgrade CVM: ${r instanceof Error?r.message:String(r)}`)}}async function Kt(t){try{return await $.delete(x.CVM_BY_APP_ID(t)),!0}catch(e){throw new Error(`Failed to delete CVM: ${e instanceof Error?e.message:String(e)}`)}}async function $e(){let t=o.startSpinner("Fetching available CVMs"),e=await Ee();if(t.stop(!0),!e||e.length===0){o.info("No CVMs found for your account");return}let r=e.map(s=>{let a=s.hosted?.app_id||s.hosted?.id,c=s.name||s.hosted?.name,l=s.status||s.hosted?.status;return{name:`${c||"Unnamed"} (${a}) - Status: ${l||"Unknown"}`,value:a}}),{selectedCvm:n}=await so.prompt([{type:"list",name:"selectedCvm",message:"Select a CVM:",choices:r}]);return n}async function qt(t){try{let e=await $.get(x.CVM_ATTESTATION(t));try{return ht.parse(e)}catch(r){return o.debug(`Validation error: ${r instanceof Error?r.message:String(r)}`),{is_online:!!e?.is_online,is_public:!!e?.is_public,error:typeof e?.error=="string"?e.error:null,app_certificates:Array.isArray(e?.app_certificates)?e.app_certificates:null,tcb_info:e?.tcb_info||null,compose_file:typeof e?.compose_file=="string"?e.compose_file:null}}}catch(e){throw new Error(`Failed to get attestation information: ${e instanceof Error?e.message:String(e)}`)}}async function Zt(t,e,r,n,s){try{let a={};if(e!==void 0&&(a.vcpu=e),r!==void 0&&(a.memory=r),n!==void 0&&(a.disk_size=n),s!==void 0&&(a.allow_restart=s),Object.keys(a).length===0)throw new Error("At least one resource parameter must be provided");return await $.patch(x.CVM_RESIZE(t),a),!0}catch(a){throw new Error(`Failed to resize CVM: ${a instanceof Error?a.message:String(a)}`)}}import We from"chalk";var Yt=new io().name("list").alias("ls").description("List all CVMs").option("-j, --json","Output in JSON format").action(async t=>{try{let e=o.startSpinner("Fetching CVMs"),r=await Ee();if(e.stop(!0),!r||r.length===0){o.info("No CVMs found");return}if(t.json){console.log(JSON.stringify(r,null,2));return}for(let n of r)o.keyValueTable({Name:n.name,"App ID":`app_${n.hosted.app_id}`,Status:n.status==="running"?We.green(n.status):n.status==="stopped"?We.red(n.status):We.yellow(n.status),"Node Info URL":n.hosted.app_url,"App URL":`${_}/dashboard/cvms/app_${n.hosted.app_id}`}),o.break();o.success(`Found ${r.length} CVMs`),o.break(),o.info(`Go to ${_}/dashboard/ to view your CVMs`)}catch(e){o.error(`Failed to list CVMs: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as ao}from"commander";import Ge from"chalk";async function D(t){if(!t){let e=await $e();return e||void 0}return await xe(t)}var Jt=new ao().name("get").description("Get details of a CVM").argument("[app-id]","App ID of the CVM (optional)").option("-j, --json","Output in JSON format").action(async(t,e)=>{try{let r=await D(t),n=o.startSpinner(`Fetching CVM with App ID app_${r}`),s=await X(r);if(n.stop(!0),o.break(),s||(o.error(`CVM with App ID app_${r} not found`),process.exit(1)),e.json){console.log(JSON.stringify(s,null,2));return}o.keyValueTable({Name:s.name,"App ID":`app_${s.app_id}`,Status:s.status==="running"?Ge.green(s.status):s.status==="stopped"?Ge.red(s.status):Ge.yellow(s.status),vCPU:s.vcpu,Memory:`${s.memory} MB`,"Disk Size":`${s.disk_size} GB`,"Dstack Image":s.base_image,"App URL":`${_}/dashboard/cvms/app_${s.app_id}`})}catch(r){o.error(`Failed to get CVM details: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as co}from"commander";var Xt=new co().name("start").description("Start a stopped CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").action(async t=>{try{let e=await D(t),r=o.startSpinner(`Starting CVM with App ID app_${e}`),n=await Bt(e);r.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being started. You can check the dashboard for more details:
|
109
109
|
${_}/dashboard/cvms/app_${n.app_id}`)}catch(e){o.error(`Failed to start CVM: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as mo}from"commander";var Qt=new mo().name("stop").description("Stop a running CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").action(async t=>{try{let e=await D(t),r=o.startSpinner(`Stopping CVM with App ID app_${e}`),n=await Wt(e);r.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being stopped. You can check the dashboard for more details:
|
110
110
|
${_}/dashboard/cvms/app_${n.app_id}`)}catch(e){o.error(`Failed to stop CVM: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as lo}from"commander";var er=new lo().name("restart").description("Restart a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").action(async t=>{try{let e=await D(t),r=o.startSpinner(`Restarting CVM with App ID app_${e}`),n=await Gt(e);r.stop(!0),o.break();let s={"CVM ID":n.id,Name:n.name,Status:n.status,"App ID":`app_${n.app_id}`,"App URL":n.app_url?n.app_url:`${_}/dashboard/cvms/app_${n.app_id}`};o.keyValueTable(s,{borderStyle:"rounded"}),o.break(),o.success(`Your CVM is being restarted. You can check the dashboard for more details:
|
111
|
-
${_}/dashboard/cvms/app_${n.app_id}`)}catch(e){o.error(`Failed to restart CVM: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as po}from"commander";import Te from"chalk";var tr=new po().name("attestation").description("Get attestation information for a CVM").argument("[app-id]","CVM app ID (will prompt for selection if not provided)").option("-j, --json","Output in JSON format").action(async(t,e)=>{try{let r;if(t)r=await xe(t);else{o.info("No CVM specified, fetching available CVMs...");let s=await $e();if(!s)return;r=s}let n=o.startSpinner(`Fetching attestation information for CVM app_${r}...`);try{let s=await qt(r);if(n.stop(!0),!s||Object.keys(s).length===0){o.info("No attestation information found");return}if(e?.json){o.info(JSON.stringify(s,null,2));return}o.success("Attestation Summary:");let a={Status:s.is_online?Te.green("Online"):Te.red("Offline"),"Public Access":s.is_public?Te.green("Enabled"):Te.yellow("Disabled"),Error:s.error||"None",Certificates:`${s.app_certificates?.length||0} found`};if(o.keyValueTable(a,{borderStyle:"rounded"}),s.app_certificates&&s.app_certificates.length>0&&s.app_certificates.forEach((c,l)=>{o.break(),o.success(`Certificate #${l+1} (${c.position_in_chain===0?"End Entity":"CA"}):`);let y={Subject:`${c.subject.common_name||"Unknown"}${c.subject.organization?` (${c.subject.organization})`:""}`,Issuer:`${c.issuer.common_name||"Unknown"}${c.issuer.organization?` (${c.issuer.organization})`:""}`,"Serial Number":c.serial_number,Validity:`${new Date(c.not_before).toLocaleString()} to ${new Date(c.not_after).toLocaleString()}`,Fingerprint:c.fingerprint,"Signature Algorithm":c.signature_algorithm,"Is CA":c.is_ca?"Yes":"No","Position in Chain":c.position_in_chain};o.keyValueTable(y,{borderStyle:"rounded"})}),s.tcb_info){o.break(),o.success("Trusted Computing Base (TCB) Information:");let c={Mrtd:s.tcb_info.mrtd,"Rootfs Hash":s.tcb_info.rootfs_hash,Rtmr0:s.tcb_info.rtmr0,Rtmr1:s.tcb_info.rtmr1,Rtmr2:s.tcb_info.rtmr2,Rtmr3:s.tcb_info.rtmr3,"Event Log Entries":`${s.tcb_info.event_log.length} entries`};if(o.keyValueTable(c,{borderStyle:"rounded"}),s.tcb_info.event_log&&s.tcb_info.event_log.length>0){o.break(),o.success("Event Log (Showing entries to reproduce RTMR3):");let l=5,y=s.tcb_info.event_log.filter(g=>g.event!==null&&g.event!=="").map(g=>({Event:g.event,IMR:g.imr.toString(),"Event Type":g.event_type.toString(),Payload:g.event_payload}));o.table(y,[{key:"Event",header:"Event",minWidth:8},{key:"IMR",header:"IMR",minWidth:3},{key:"Event Type",header:"Type",minWidth:8},{key:"Payload",header:"Payload",minWidth:25}]),s.tcb_info.event_log.length>l&&o.info("To see all full attestation data, use --json"),o.break(),o.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(s){throw n.stop(!1),s}}catch(r){o.error(`Failed to get attestation information: ${r instanceof Error?r.message:String(r)}`)}});import{Command as go}from"commander";import{z as uo}from"zod";async function He(){try{let t=await $.get(x.TEEPODS);return gt.parse(t).nodes}catch(t){throw new Error(`Failed to get TEEPods: ${t instanceof Error?t.message:String(t)}`)}}async function rr(t){try{let r=(await He()).find(s=>s.teepod_id===Number(t));if(r&&r.images&&r.images.length>0)return r.images;let n=await $.get(x.TEEPOD_IMAGES(t));return uo.array(Oe).parse(n)}catch(e){throw new Error(`Failed to get TEEPod images: ${e instanceof Error?e.message:String(e)}`)}}import{encryptEnvVars as ho}from"@phala/dstack-sdk/encrypt-env-vars";import or from"fs";import yo from"path";import ge from"inquirer";import fo from"node:fs";var fe=(t,e)=>{let r={};if(t){for(let n of t)if(n.includes("=")){let[s,a]=n.split("=");s&&a&&(r[s]=a)}}if(e){let n=fo.readFileSync(e,"utf8");for(let s of n.split(`
|
112
|
-
`))if(!(!s.trim()||s.trim().startsWith("#"))&&s.includes("=")){let[a,...c]=s.split("="),l=c.join("="),y=l.search(/\s+#/);y!==-1&&(l=l.substring(0,y).trim()),a&&l&&(r[a.trim()]=l.trim())}}return Object.entries(r).map(([n,s])=>({key:n,value:s}))};var nr=new go().name("create").description("Create a new CVM").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file").option("--vcpu <vcpu>","Number of vCPUs",String(oe)).option("--memory <memory>","Memory in MB",String(ne)).option("--disk-size <diskSize>","Disk size in GB",String(se)).option("--teepod-id <teepodId>","TEEPod ID to use",nt).option("--image <image>","Version of dstack image to use",st).option("-e, --env-file <envFile>","Path to environment file").option("--skip-env","Skip environment variable prompt",!1).option("--debug","Enable debug mode",!1).action(async t=>{try{if(!t.name){let{name:m}=await ge.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:d=>d.trim()?!0:"CVM name is required"}]);t.name=m}if(!t.compose){let d=we(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");t.compose=await B("Enter the path to your Docker Compose file:",d,"file")}let e=yo.resolve(t.compose);or.existsSync(e)||(o.error(`Docker Compose file not found: ${e}`),process.exit(1));let r=or.readFileSync(e,"utf8");await W();let n=[];if(t.envFile)try{n=fe([],t.envFile)}catch(m){o.error(`Failed to read environment file: ${m instanceof Error?m.message:String(m)}`),process.exit(1)}else if(!t.skipEnv)
|
111
|
+
${_}/dashboard/cvms/app_${n.app_id}`)}catch(e){o.error(`Failed to restart CVM: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as po}from"commander";import Te from"chalk";var tr=new po().name("attestation").description("Get attestation information for a CVM").argument("[app-id]","CVM app ID (will prompt for selection if not provided)").option("-j, --json","Output in JSON format").action(async(t,e)=>{try{let r;if(t)r=await xe(t);else{o.info("No CVM specified, fetching available CVMs...");let s=await $e();if(!s)return;r=s}let n=o.startSpinner(`Fetching attestation information for CVM app_${r}...`);try{let s=await qt(r);if(n.stop(!0),!s||Object.keys(s).length===0){o.info("No attestation information found");return}if(e?.json){o.info(JSON.stringify(s,null,2));return}o.success("Attestation Summary:");let a={Status:s.is_online?Te.green("Online"):Te.red("Offline"),"Public Access":s.is_public?Te.green("Enabled"):Te.yellow("Disabled"),Error:s.error||"None",Certificates:`${s.app_certificates?.length||0} found`};if(o.keyValueTable(a,{borderStyle:"rounded"}),s.app_certificates&&s.app_certificates.length>0&&s.app_certificates.forEach((c,l)=>{o.break(),o.success(`Certificate #${l+1} (${c.position_in_chain===0?"End Entity":"CA"}):`);let y={Subject:`${c.subject.common_name||"Unknown"}${c.subject.organization?` (${c.subject.organization})`:""}`,Issuer:`${c.issuer.common_name||"Unknown"}${c.issuer.organization?` (${c.issuer.organization})`:""}`,"Serial Number":c.serial_number,Validity:`${new Date(c.not_before).toLocaleString()} to ${new Date(c.not_after).toLocaleString()}`,Fingerprint:c.fingerprint,"Signature Algorithm":c.signature_algorithm,"Is CA":c.is_ca?"Yes":"No","Position in Chain":c.position_in_chain};o.keyValueTable(y,{borderStyle:"rounded"})}),s.tcb_info){o.break(),o.success("Trusted Computing Base (TCB) Information:");let c={Mrtd:s.tcb_info.mrtd,"Rootfs Hash":s.tcb_info.rootfs_hash,Rtmr0:s.tcb_info.rtmr0,Rtmr1:s.tcb_info.rtmr1,Rtmr2:s.tcb_info.rtmr2,Rtmr3:s.tcb_info.rtmr3,"Event Log Entries":`${s.tcb_info.event_log.length} entries`};if(o.keyValueTable(c,{borderStyle:"rounded"}),s.tcb_info.event_log&&s.tcb_info.event_log.length>0){o.break(),o.success("Event Log (Showing entries to reproduce RTMR3):");let l=5,y=s.tcb_info.event_log.filter(g=>g.event!==null&&g.event!=="").map(g=>({Event:g.event,IMR:g.imr.toString(),"Event Type":g.event_type.toString(),Payload:g.event_payload}));o.table(y,[{key:"Event",header:"Event",minWidth:8},{key:"IMR",header:"IMR",minWidth:3},{key:"Event Type",header:"Type",minWidth:8},{key:"Payload",header:"Payload",minWidth:25}]),s.tcb_info.event_log.length>l&&o.info("To see all full attestation data, use --json"),o.break(),o.success("To reproduce RTMR3, use the tool at https://rtmr3-calculator.vercel.app/")}}}catch(s){throw n.stop(!1),s}}catch(r){o.error(`Failed to get attestation information: ${r instanceof Error?r.message:String(r)}`)}});import{Command as go}from"commander";import{z as uo}from"zod";async function He(){try{let t=await $.get(x.TEEPODS);return gt.parse(t).nodes}catch(t){throw new Error(`Failed to get TEEPods: ${t instanceof Error?t.message:String(t)}`)}}async function rr(t){try{let r=(await He()).find(s=>s.teepod_id===Number(t));if(r&&r.images&&r.images.length>0)return r.images;let n=await $.get(x.TEEPOD_IMAGES(t));return uo.array(Oe).parse(n)}catch(e){throw new Error(`Failed to get TEEPod images: ${e instanceof Error?e.message:String(e)}`)}}import{encryptEnvVars as ho}from"@phala/dstack-sdk/encrypt-env-vars";import or from"node:fs";import yo from"node:path";import ge from"inquirer";import fo from"node:fs";var fe=(t,e)=>{let r={};if(t){for(let n of t)if(n.includes("=")){let[s,a]=n.split("=");s&&a&&(r[s]=a)}}if(e){let n=fo.readFileSync(e,"utf8");for(let s of n.split(`
|
112
|
+
`))if(!(!s.trim()||s.trim().startsWith("#"))&&s.includes("=")){let[a,...c]=s.split("="),l=c.join("="),y=l.search(/\s+#/);y!==-1&&(l=l.substring(0,y).trim()),a&&l&&(r[a.trim()]=l.trim())}}return Object.entries(r).map(([n,s])=>({key:n,value:s}))};var nr=new go().name("create").description("Create a new CVM").option("-n, --name <name>","Name of the CVM").option("-c, --compose <compose>","Path to Docker Compose file").option("--vcpu <vcpu>","Number of vCPUs",String(oe)).option("--memory <memory>","Memory in MB",String(ne)).option("--disk-size <diskSize>","Disk size in GB",String(se)).option("--teepod-id <teepodId>","TEEPod ID to use",nt).option("--image <image>","Version of dstack image to use",st).option("-e, --env-file <envFile>","Path to environment file").option("--skip-env","Skip environment variable prompt",!1).option("--debug","Enable debug mode",!1).action(async t=>{try{if(!t.name){let{name:m}=await ge.prompt([{type:"input",name:"name",message:"Enter a name for the CVM:",validate:d=>d.trim()?!0:"CVM name is required"}]);t.name=m}if(!t.compose){let d=we(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");t.compose=await B("Enter the path to your Docker Compose file:",d,"file")}let e=yo.resolve(t.compose);or.existsSync(e)||(o.error(`Docker Compose file not found: ${e}`),process.exit(1));let r=or.readFileSync(e,"utf8");await W();let n=[];if(t.envFile)try{n=fe([],t.envFile)}catch(m){o.error(`Failed to read environment file: ${m instanceof Error?m.message:String(m)}`),process.exit(1)}else if(!t.skipEnv){let{shouldSkip:m}=await ge.prompt([{type:"confirm",name:"shouldSkip",message:"Do you want to skip environment variable prompt?",default:!0}]);if(o.info("shouldSkip",m),m)o.info("Skipping environment variable prompt");else{let d=await B("Enter the path to your environment file:",".env","file");n=fe([],d)}}let s=[];if(t.vcpu===String(oe)&&s.push({type:"input",name:"vcpu",message:`Enter number of vCPUs (default: ${oe}):`,default:String(oe),validate:m=>{let d=parseInt(m);return isNaN(d)||d<=0?"Please enter a valid positive number":!0}}),t.memory===String(ne)&&s.push({type:"input",name:"memory",message:`Enter memory in MB (default: ${ne}):`,default:String(ne),validate:m=>{let d=parseInt(m);return isNaN(d)||d<=0?"Please enter a valid positive number":!0}}),t.diskSize===String(se)&&s.push({type:"input",name:"diskSize",message:`Enter disk size in GB (default: ${se}):`,default:String(se),validate:m=>{let d=parseInt(m);return isNaN(d)||d<=0?"Please enter a valid positive number":!0}}),s.length>0){let m=await ge.prompt(s);m.vcpu&&(t.vcpu=m.vcpu),m.memory&&(t.memory=m.memory),m.diskSize&&(t.diskSize=m.diskSize)}if(!t.teepodId){let m=o.startSpinner("Fetching available TEEPods"),d=await He();m.stop(!0),d.length===0&&(o.error("No TEEPods available. Please try again later."),process.exit(1));let{selectedTeepodId:f}=await ge.prompt([{type:"list",name:"selectedTeepodId",message:"Select a TEEPod:",choices:d.map(u=>({name:`${u.name}`,value:u.teepod_id}))}]),h=d.find(u=>u.teepod_id===f);h||(o.error("Failed to find selected TEEPod"),process.exit(1)),o.info(`Selected TEEPod: ${h.name}`),t.teepodId=h.teepod_id}if(!t.image){let d=(await rr(t.teepodId)).map(h=>({name:`${h.name}`,value:h.name})),{selectedImage:f}=await ge.prompt([{type:"list",name:"selectedImage",message:"Select an image:",choices:d}]);t.image=f.value}let a={teepod_id:t.teepodId||3,name:t.name,image:t.image||"dstack-dev-0.3.5",vcpu:parseInt(t.vcpu),memory:parseInt(t.memory),disk_size:parseInt(t.diskSize),compose_manifest:{docker_compose_file:r,docker_config:{url:"",username:"",password:""},features:["kms","tproxy-net"],kms_enabled:!0,manifest_version:2,name:t.name,public_logs:!0,public_sysinfo:!0,tproxy_enabled:!0},listed:!1},c=o.startSpinner("Getting public key from CVM"),l=await zt(a);c.stop(!0),l||(o.error("Failed to get public key from CVM"),process.exit(1));let y=o.startSpinner("Encrypting environment variables"),g=await ho(n,l.app_env_encrypt_pubkey);y.stop(!0),t.debug&&(o.debug("Public key:",l.app_env_encrypt_pubkey),o.debug("Encrypted environment variables:",g),o.debug("Environment variables:",JSON.stringify(n)));let k=o.startSpinner("Creating CVM"),b=await jt({...a,encrypted_env:g,app_env_encrypt_pubkey:l.app_env_encrypt_pubkey,app_id_salt:l.app_id_salt});k.stop(!0),b||(o.error("Failed to create CVM"),process.exit(1)),o.success("CVM created successfully"),o.break();let p={"CVM ID":b.id,Name:b.name,Status:b.status,"App ID":`app_${b.app_id}`,"App URL":b.app_url?b.app_url:`${_}/dashboard/cvms/app_${b.app_id}`};o.keyValueTable(p,{borderStyle:"rounded"}),o.info(""),o.success(`Your CVM is being created. You can check its status with:
|
113
113
|
phala cvms get app_${b.app_id}`)}catch(e){o.error(`Failed to create CVM: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});import{Command as bo}from"commander";import vo from"inquirer";var sr=new bo().name("delete").description("Delete a CVM").argument("[app-id]","App ID of the CVM to delete (if not provided, a selection prompt will appear)").option("-f, --force","Skip confirmation prompt",!1).action(async(t,e)=>{try{let r=await D(t);if(!e.force){let{confirm:a}=await vo.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete CVM with App ID app_${r}? This action cannot be undone.`,default:!1}]);if(!a){o.info("Deletion cancelled");return}}let n=o.startSpinner(`Deleting CVM app_${r}`),s=await Kt(r);n.stop(!0),s||(o.error(`Failed to delete CVM app_${r}`),process.exit(1)),o.success(`CVM app_${r} deleted successfully`)}catch(r){o.error(`Failed to delete CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as Co}from"commander";import ko from"node:fs";import{encryptEnvVars as wo}from"@phala/dstack-sdk/encrypt-env-vars";var ir=new Co().name("upgrade").description("Upgrade a CVM to a new version").argument("[app-id]","CVM app ID to upgrade (will prompt for selection if not provided)").option("-c, --compose <compose>","Path to new Docker Compose file").option("-e, --env-file <envFile>","Path to environment file").option("--debug","Enable debug mode",!1).action(async(t,e)=>{try{let r=await D(t),n=o.startSpinner(`Fetching current configuration for CVM app_${r}`),s=await X(r);if(n.stop(!0),s||(o.error(`CVM with App ID app_${r} not found`),process.exit(1)),!e.compose){let b=we(["docker-compose.yml","docker-compose.yaml"],"Detected docker compose file: {path}");e.compose=await B("Enter the path to your Docker Compose file:",b,"file")}let a="";if(e.compose)try{a=ko.readFileSync(e.compose,"utf8")}catch(k){o.error(`Failed to read Docker Compose file: ${k instanceof Error?k.message:String(k)}`),process.exit(1)}await W();let c="";if(e.envFile){let k=[];if(e.envFile)try{k=fe([],e.envFile),c=await wo(k,s.encrypted_env_pubkey)}catch(b){o.error(`Failed to read environment file: ${b instanceof Error?b.message:String(b)}`),process.exit(1)}}let l={compose_manifest:{docker_compose_file:a,manifest_version:1,runner:"docker-compose",version:"1.0.0",features:["kms","tproxy-net"],name:`app_${r}`},encrypted_env:c,allow_restart:!0},y=o.startSpinner(`Upgrading CVM app_${r}`),g=await Ht(r,l);g||(y.stop(!1),o.error("Failed to upgrade CVM"),process.exit(1)),y.stop(!0),g.detail&&o.info(`Details: ${g.detail}`),o.break(),o.success(`Your CVM is being upgraded. You can check the dashboard for more details:
|
114
114
|
${_}/dashboard/cvms/app_${r}`)}catch(r){o.error(`Failed to upgrade CVM: ${r instanceof Error?r.message:String(r)}`),process.exit(1)}});import{Command as So}from"commander";import he from"inquirer";import N from"chalk";var ar=new So().name("resize").description("Resize resources for a CVM").argument("[app-id]","App ID of the CVM (if not provided, a selection prompt will appear)").option("-v, --vcpu <vcpu>","Number of virtual CPUs").option("-m, --memory <memory>","Memory size in MB").option("-d, --disk-size <diskSize>","Disk size in GB").option("-r, --allow-restart <allowRestart>","Allow restart of the CVM if needed for resizing").option("-y, --yes","Automatically confirm the resize operation").action(async(t,e)=>{try{let r=await D(t),n=await X(r),s=e.vcpu,a=e.memory,c=e.diskSize,l=e.allowRestart;s||(s=(await he.prompt([{type:"input",name:"vcpu",message:"Enter number of vCPUs:",validate:p=>{let m=parseInt(p);return isNaN(m)||m<0?"Please enter a valid non-negative number":!0},default:n.vcpu,filter:p=>parseInt(p)}])).vcpu),a||(a=(await he.prompt([{type:"input",name:"memory",message:"Enter memory in MB:",validate:p=>{let m=parseInt(p);return isNaN(m)||m<0?"Please enter a valid non-negative number":!0},default:n.memory,filter:p=>parseInt(p)}])).memory),c||(c=(await he.prompt([{type:"input",name:"diskSize",message:"Enter disk size in GB:",validate:p=>{let m=parseInt(p);return isNaN(m)||m<0?"Please enter a valid non-negative number":!0},default:n.disk_size,filter:p=>parseInt(p)}])).diskSize),l||(l=(await he.prompt([{type:"confirm",name:"allowRestart",message:"Allow restart of the CVM if needed for resizing?",default:!1}])).allowRestart);let y=`Are you sure you want to resize CVM app_${r} with the following changes:
|
115
115
|
`;if(o.keyValueTable({vCPUs:n.vcpu!==s?`${N.red(n.vcpu)} -> ${N.green(s)}`:n.vcpu,Memory:n.memory!==a?`${N.red(n.memory)} MB -> ${N.green(a)} MB`:n.memory,"Disk Size":n.disk_size!==c?`${N.red(n.disk_size)} GB -> ${N.green(c)} GB`:n.disk_size,"Allow Restart":l?N.green("Yes"):N.red("No")}),!e.yes){let{confirm:b}=await he.prompt([{type:"confirm",name:"confirm",message:y,default:!1}]);if(!b){o.info("Resize operation cancelled");return}}let g=o.startSpinner(`Resizing CVM with App ID app_${r}`);await Zt(r,s,a,c,l?1:0),g.stop(!0),o.break(),o.success(`Your CVM is being resized. You can check the dashboard for more details:
|