Skip to content

Commit 29bfbbf

Browse files
authored
Hide environments user can't access (#704)
* Hide environments user can't access Makes env level RBAC experience better in CLI
1 parent 407c5ac commit 29bfbbf

File tree

7 files changed

+3461
-1776
lines changed

7 files changed

+3461
-1776
lines changed

src/commands/environment.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,19 @@ async fn delete_environment(args: DeleteArgs) -> Result<()> {
161161
bail!(RailwayError::EnvironmentNotFound(environment))
162162
}
163163
} else if is_terminal {
164-
let environments = project
165-
.environments
166-
.edges
164+
let all_environments = &project.environments.edges;
165+
let environments = all_environments
167166
.iter()
167+
.filter(|env| env.node.can_access)
168168
.map(|env| Environment(&env.node))
169169
.collect::<Vec<_>>();
170+
if environments.is_empty() {
171+
if all_environments.is_empty() {
172+
bail!("Project has no environments");
173+
} else {
174+
bail!("All environments in this project are restricted");
175+
}
176+
}
170177
let r = prompt_options("Select the environment to delete", environments)?;
171178
(r.0.id.clone(), r.0.name.clone())
172179
} else {
@@ -240,13 +247,21 @@ async fn link_environment(args: Args) -> std::result::Result<(), anyhow::Error>
240247
bail!(RailwayError::ProjectDeleted);
241248
}
242249

243-
let environments = project
244-
.environments
245-
.edges
250+
let all_environments = &project.environments.edges;
251+
let environments = all_environments
246252
.iter()
253+
.filter(|env| env.node.can_access)
247254
.map(|env| Environment(&env.node))
248255
.collect::<Vec<_>>();
249256

257+
if environments.is_empty() {
258+
if all_environments.is_empty() {
259+
bail!("Project has no environments");
260+
} else {
261+
bail!("All environments in this project are restricted");
262+
}
263+
}
264+
250265
let environment = match args.environment {
251266
// If the environment is specified, find it in the list of environments
252267
Some(environment) => {
@@ -474,6 +489,7 @@ fn select_duplicate_id_new(
474489
.environments
475490
.edges
476491
.iter()
492+
.filter(|env| env.node.can_access)
477493
.map(|env| Environment(&env.node))
478494
.collect::<Vec<_>>();
479495
prompt_options_skippable(

src/commands/link.rs

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ fn select_environment(
128128
environment: Option<String>,
129129
project: &NormalisedProject,
130130
) -> Result<NormalisedEnvironment, anyhow::Error> {
131+
if project.environments.is_empty() {
132+
if project.has_restricted_environments {
133+
bail!("All environments in this project are restricted");
134+
} else {
135+
bail!("Project has no environments");
136+
}
137+
}
138+
131139
let environment = if let Some(environment) = environment {
132140
let env = project.environments.iter().find(|e| {
133141
(e.name.to_lowercase() == environment.to_lowercase())
@@ -260,7 +268,9 @@ structstruck::strike! {
260268
///
261269
/// _**note**_: this isn't what the API returns, we are just extracting what we need
262270
service_instances: Vec<String>,
263-
}>
271+
}>,
272+
/// Whether the project has restricted environments
273+
has_restricted_environments: bool,
264274
}
265275
}
266276

@@ -269,62 +279,76 @@ structstruck::strike! {
269279
impl From<Project> for NormalisedProject {
270280
fn from(value: Project) -> Self {
271281
match value {
272-
Project::External(project) => NormalisedProject::new(
273-
project.id,
274-
project.name,
275-
project
282+
Project::External(project) => {
283+
let total_envs = project.environments.edges.len();
284+
let accessible_envs: Vec<_> = project
276285
.environments
277286
.edges
278287
.into_iter()
288+
.filter(|env| env.node.can_access)
279289
.map(|env| NormalisedEnvironment::new(env.node.id, env.node.name))
280-
.collect(),
281-
project
282-
.services
283-
.edges
284-
.into_iter()
285-
.map(|service| {
286-
NormalisedService::new(
287-
service.node.id,
288-
service.node.name,
289-
service
290-
.node
291-
.service_instances
292-
.edges
293-
.into_iter()
294-
.map(|instance| instance.node.environment_id)
295-
.collect(),
296-
)
297-
})
298-
.collect(),
299-
),
300-
Project::Workspace(project) => NormalisedProject::new(
301-
project.id,
302-
project.name,
303-
project
290+
.collect();
291+
let has_restricted = total_envs > accessible_envs.len();
292+
NormalisedProject::new(
293+
project.id,
294+
project.name,
295+
accessible_envs,
296+
project
297+
.services
298+
.edges
299+
.into_iter()
300+
.map(|service| {
301+
NormalisedService::new(
302+
service.node.id,
303+
service.node.name,
304+
service
305+
.node
306+
.service_instances
307+
.edges
308+
.into_iter()
309+
.map(|instance| instance.node.environment_id)
310+
.collect(),
311+
)
312+
})
313+
.collect(),
314+
has_restricted,
315+
)
316+
}
317+
Project::Workspace(project) => {
318+
let total_envs = project.environments.edges.len();
319+
let accessible_envs: Vec<_> = project
304320
.environments
305321
.edges
306322
.into_iter()
323+
.filter(|env| env.node.can_access)
307324
.map(|env| NormalisedEnvironment::new(env.node.id, env.node.name))
308-
.collect(),
309-
project
310-
.services
311-
.edges
312-
.into_iter()
313-
.map(|service| {
314-
NormalisedService::new(
315-
service.node.id,
316-
service.node.name,
317-
service
318-
.node
319-
.service_instances
320-
.edges
321-
.into_iter()
322-
.map(|instance| instance.node.environment_id)
323-
.collect(),
324-
)
325-
})
326-
.collect(),
327-
),
325+
.collect();
326+
let has_restricted = total_envs > accessible_envs.len();
327+
NormalisedProject::new(
328+
project.id,
329+
project.name,
330+
accessible_envs,
331+
project
332+
.services
333+
.edges
334+
.into_iter()
335+
.map(|service| {
336+
NormalisedService::new(
337+
service.node.id,
338+
service.node.name,
339+
service
340+
.node
341+
.service_instances
342+
.edges
343+
.into_iter()
344+
.map(|instance| instance.node.environment_id)
345+
.collect(),
346+
)
347+
})
348+
.collect(),
349+
has_restricted,
350+
)
351+
}
328352
}
329353
}
330354
}

src/controllers/terminal/client.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ impl TerminalClient {
4949
.map_err(|e| anyhow::anyhow!("Failed to parse server message: {}", e))?;
5050

5151
if server_msg.r#type != "welcome" {
52+
// If it's an error message, extract and display the actual error message
53+
if server_msg.r#type == "error" && !server_msg.payload.message.is_empty() {
54+
bail!("Failed to connect: {}", server_msg.payload.message);
55+
}
5256
bail!("Expected welcome message, received: {:?}", server_msg);
5357
}
5458

src/gql/queries/strings/Project.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ query Project($id: String!) {
1111
node {
1212
id
1313
name
14+
canAccess
1415
deletedAt
1516
}
1617
}

src/gql/queries/strings/UserProjects.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ query UserProjects {
1414
node {
1515
id
1616
name
17+
canAccess
1718
}
1819
}
1920
}
@@ -54,6 +55,7 @@ query UserProjects {
5455
node {
5556
id
5657
name
58+
canAccess
5759
}
5860
}
5961
}

0 commit comments

Comments
 (0)