# Agente CtrlStation - MacOS

## CtrlStationAgent - MacOS

Este documento é voltado ao **CtrlStationAgent** em estações de trabalho macOS gerenciadas. Ele explica o que o agente faz, como instalá-lo e desinstalá-lo, como conceder as permissões necessárias e como ler os logs em caso de problemas.

---

### O que o agente faz

O CtrlStationAgent é um pequeno **agente em segundo plano** (sem ícone no Dock e sem janela principal) que aplica a política de sessão da estação de trabalho em nome do backend do CtrlStation. No Mac de cada usuário, ele:

- **Reporta eventos de sessão** ao backend: logon, bloqueio de tela, desbloqueio de tela e logout.
- **Consulta o backend a cada 30 segundos** (`/user/status`). Se o backend marcar o usuário como *bloqueado*, o agente aplica a ação configurada: 
    - **Bloquear a tela**, ou
    - **Encerrar a sessão do usuário (logout)**.
- **Reaplica o bloqueio ao desbloquear.** Se um usuário bloqueado desbloquear a tela, o agente reconsulta o backend; se o usuário continuar bloqueado, exibe o aviso **"Acesso Bloqueado"** e bloqueia novamente (ou faz logout) após ~2 segundos. Se o backend estiver inacessível nesse momento, o usuário permanece desbloqueado (comportamento "fail-open").
- **Exibe mensagens enviadas pelo servidor** ao usuário em pequenas janelas pop-up não bloqueantes. Cada mensagem é exibida apenas uma vez por máquina.

Ele é executado **uma vez por usuário logado**, inicia automaticamente no login e é reiniciado automaticamente caso pare.

> **Atenção ao impacto no usuário:** quando o backend bloqueia um usuário, a tela dele será bloqueada ou ele será deslogado — possivelmente de forma repetida até que o backend remova o bloqueio. Certifique-se de que a política do backend esteja correta antes de uma implantação ampla.

---

### Requisitos

<table id="bkmrk-requisito-detalhe-ve"><thead><tr><th>Requisito</th><th>Detalhe</th></tr></thead><tbody><tr><td>Versão do macOS</td><td>**macOS 26.0 ou superior** (deployment target do build). Macs mais antigos não executarão o agente, a menos que o app seja recompilado com um target menor.</td></tr><tr><td>Privilégios</td><td>Direitos de administrador para instalar (o pacote grava em `/Applications` e `/Library`).</td></tr><tr><td>Rede</td><td>HTTPS de saída para o backend configurado, atualmente `https://[cliente].ctrlstation.com/api`.</td></tr><tr><td>Permissões</td><td>Automação (Apple Events) e Acessibilidade — ver Seção 4.</td></tr><tr><td>Assinatura</td><td>O pacote é assinado com um **Developer ID** da LAB3 e **notarizado**, portanto instala sem avisos do Gatekeeper.</td></tr></tbody></table>

---

### Instalação

O entregável é um pacote instalador assinado e notarizado, por exemplo **`CtrlStationAgent-v1.3.3.pkg`**. O link para download é fornecido pela LAB3 ou pelo seu parceiro de revenda

#### Opção A — Interativa (máquina única)

1. Dê um duplo-clique no `.pkg`.
2. Siga o instalador e autentique-se como administrador quando solicitado.

#### Opção B — Linha de comando / script

```sh
sudo installer -pkg /caminho/para/CtrlStationAgent-v1.3.3.pkg -target /
```

#### Opção C — MDM (implantação em frota)

Envie o `.pkg` para o seu MDM (Jamf, Kandji, Mosyle, Intune, etc.) e direcione-o às máquinas-alvo. Envie também o perfil de privacidade (PPPC) descrito na Seção 4 para que o agente funcione sem prompts de permissão por usuário.

#### O que o instalador faz

O script `postinstall` do pacote automaticamente:

- Instala o app em `/Applications/CtrlStationAgent.app`.
- Grava o arquivo de configuração (URL do backend + token de acesso) em `/Library/Application Support/CtrlStationAgent/config.json` e restringe sua propriedade/permissões (`root:wheel`, `644`).
- Instala o LaunchAgent em `/Library/LaunchAgents/com.lab3dvlp.CtrlStationAgent.plist`.
- Inicia o agente imediatamente para o usuário logado no console naquele momento. Os demais usuários recebem o agente automaticamente no próximo login.

Não é necessário reiniciar.

---

### Permissões 

Sob a proteção de privacidade do macOS (TCC), o agente precisa de duas permissões para executar todas as suas ações:

<table id="bkmrk-permiss%C3%A3o-por-qu%C3%AA-qu"><thead><tr><th>Permissão</th><th>Por quê</th><th>Quando é necessária</th></tr></thead><tbody><tr><td>**Automação → System Events** (Apple Events)</td><td>Usada para encerrar a sessão do usuário de forma controlada.</td><td>Quando a ação do backend é "logout".</td></tr><tr><td>**Acessibilidade**</td><td>Mecanismo alternativo para bloquear a tela via simulação de tecla, caso o método principal de bloqueio não esteja disponível em determinada versão do macOS.</td><td>Raramente — apenas se o método de bloqueio silencioso preferencial falhar.</td></tr></tbody></table>

Em um Mac não gerenciado, o macOS exibirá um prompt único na primeira vez que o agente tentar essas ações (por exemplo, *"CtrlStationAgent deseja controlar o System Events"*). O usuário precisa clicar em **OK** / ativar a opção em **Ajustes do Sistema → Privacidade e Segurança**.

**Para implantação em frota, pré-aprove essas permissões com um perfil PPPC (Privacy Preferences Policy Control) via MDM**, para que os usuários nunca vejam prompts e a aplicação da política nunca seja bloqueada:

- **Identificador:** `com.lab3dvlp.CtrlStationAgent` (Bundle ID)
- **Tipo de identificador:** Bundle ID
- **Requisito de código (code requirement):**```
    identifier "com.lab3dvlp.CtrlStationAgent" and anchor apple generic and certificate leaf[subject.OU] = "S9DE935KXJ"
    
    ```
- **Serviços a permitir:**
    - `SystemPolicyAllFiles` — não é necessário.
    - **Apple Events** — permitir, com destino **`com.apple.systemevents`**.
    - **Acessibilidade** — permitir.

> Em algumas versões do macOS, a Acessibilidade não pode ser concedida por um payload PPPC isolado; a maioria dos MDMs oferece um controle dedicado de "Acessibilidade" no editor de PPPC. Conceda por lá.

---

### Verificar se está em execução

Execute na máquina-alvo (como o usuário logado):

```sh
# O processo está ativo?
pgrep -lf CtrlStationAgent

# Status do LaunchAgent (procure por "state = running" e o caminho do programa)
launchctl print "gui/$(id -u)/com.lab3dvlp.CtrlStationAgent" | grep -E "state|program"

```

Um agente saudável reporta `state = running` e um caminho de programa `/Applications/CtrlStationAgent.app/Contents/MacOS/CtrlStationAgent`.

Confirme se a configuração foi aplicada corretamente (admin):

```sh
sudo cat "/Library/Application Support/CtrlStationAgent/config.json"

```

---

### Verificar os logs

O agente registra através do **sistema de logs unificado** do macOS (não há arquivos de log separados). Use o Console.app ou o comando `log`, filtrando pelo subsistema do agente.

```sh
# Acompanhamento ao vivo — deixe rodando e então bloqueie/desbloqueie ou aguarde um heartbeat:
log stream --predicate 'subsystem == "com.lab3dvlp.CtrlStationAgent"'

# Histórico recente (última hora). Adicione --debug para incluir as linhas de nível
# debug (heartbeats, etc.), que NÃO são persistidas por padrão:
log show --debug --predicate 'subsystem == "com.lab3dvlp.CtrlStationAgent"' --last 1h

```

Você pode restringir a uma área usando o campo `category`. Categorias disponíveis: `app`, `api`, `events`, `heartbeat`, `session`, `notifications`, `action`, `config`.

```sh
# Apenas eventos de sessão e atividade de aplicação de política:
log stream --predicate 'subsystem == "com.lab3dvlp.CtrlStationAgent" AND (category == "events" OR category == "action")'

```

No **Console.app**: abra-o, inicie o streaming e digite o subsistema `com.lab3dvlp.CtrlStationAgent` na barra de busca (defina o filtro como "Subsistema").

O que você normalmente verá: `Evento detectado: Tela Bloqueada/Desbloqueada`, `Executando heartbeat...`, `API confirmou bloqueio; reaplicando em 2s` e `Exibindo notificação customizada: …` para mensagens do servidor.

---

### Solução de problemas

<table id="bkmrk-sintoma-verifica%C3%A7%C3%A3o-"><thead><tr><th>Sintoma</th><th>Verificação</th></tr></thead><tbody><tr><td>Agente não está em execução</td><td>`pgrep -lf CtrlStationAgent`. Se vazio, confirme que o plist existe em `/Library/LaunchAgents/com.lab3dvlp.CtrlStationAgent.plist` e o app em `/Applications/CtrlStationAgent.app`. Peça ao usuário para sair/entrar novamente, ou inicie manualmente (Seção 8).</td></tr><tr><td>Agente inicia e encerra</td><td>Configuração ausente/inválida. O agente encerra se o `config.json` estiver ausente ou malformado. Verifique `/Library/Application Support/CtrlStationAgent/config.json`. Consulte a categoria de log `config`.</td></tr><tr><td>Eventos não chegam ao backend</td><td>Acessibilidade de rede/API. Verifique as categorias de log `api` e `events` em busca de erros; confirme o HTTPS de saída para a URL do backend.</td></tr><tr><td>Ação de logout não faz nada</td><td>Permissão de Apple Events (Automação) não concedida. Ver Seção 4. Verifique as categorias `action`/`session`.</td></tr><tr><td>A tela não bloqueia</td><td>Raro — verifique a categoria `session`; o mecanismo alternativo por tecla requer Acessibilidade (Seção 4).</td></tr><tr><td>Mensagens do servidor não aparecem</td><td>Cada mensagem é exibida apenas **uma vez por máquina** (registrada no arquivo por usuário da Seção 9). Uma mensagem já vista não reaparecerá.</td></tr></tbody></table>

---

### Iniciar / parar / reiniciar o agente manualmente

Execute como o usuário logado (estes comandos atuam na sessão GUI desse usuário):

```sh
# Parar (descarregar)
launchctl bootout "gui/$(id -u)/com.lab3dvlp.CtrlStationAgent"

# Iniciar (carregar)
launchctl bootstrap "gui/$(id -u)" /Library/LaunchAgents/com.lab3dvlp.CtrlStationAgent.plist

# Reiniciar = bootout e depois bootstrap

```

Para atuar na sessão de outro usuário, substitua `$(id -u)` pelo UID numérico daquele usuário (descubra-o com `id -u <nome_do_usuario>`); esses comandos exigem admin/root.

---

### Desinstalação

Não há pacote desinstalador; remova os componentes manualmente ou via script no MDM.

```sh
# 1. Pare o agente para o usuário logado (repita por usuário logado / UID)
launchctl bootout "gui/$(id -u)/com.lab3dvlp.CtrlStationAgent" 2>/dev/null

# 2. Remova a definição do LaunchAgent (admin)
sudo rm -f /Library/LaunchAgents/com.lab3dvlp.CtrlStationAgent.plist

# 3. Remova o aplicativo (admin)
sudo rm -rf /Applications/CtrlStationAgent.app

# 4. Remova a configuração do sistema (admin) — isto apaga o token do backend
sudo rm -rf "/Library/Application Support/CtrlStationAgent"

# 5. Esqueça o recibo do instalador (admin)
sudo pkgutil --forget com.lab3dvlp.CtrlStationAgent

# 6. Remova os dados por usuário (execute para CADA conta que tenha feito login)
rm -rf "$HOME/Library/Application Support/CtrlStationAgent"

```

Após a remoção, opcionalmente remova o perfil PPPC do MDM, caso tenha enviado um.

> Remover o plist do LaunchAgent e o app e, em seguida, fazer o usuário sair/entrar novamente já é suficiente para interromper a aplicação da política. Os passos 4 a 6 são limpeza.

---

### Referência

<table id="bkmrk-item-valor-bundle-do"><thead><tr><th>Item</th><th>Valor</th></tr></thead><tbody><tr><td>Bundle do app</td><td>`/Applications/CtrlStationAgent.app`</td></tr><tr><td>Identificador do bundle / label do LaunchAgent</td><td>`com.lab3dvlp.CtrlStationAgent`</td></tr><tr><td>Plist do LaunchAgent</td><td>`/Library/LaunchAgents/com.lab3dvlp.CtrlStationAgent.plist`</td></tr><tr><td>Arquivo de configuração</td><td>`/Library/Application Support/CtrlStationAgent/config.json`</td></tr><tr><td>Dados por usuário (mensagens já vistas)</td><td>`~/Library/Application Support/CtrlStationAgent/`</td></tr><tr><td>API do backend</td><td>`https://[cliente].ctrlstation.com/api` (definida no `config.json`)</td></tr><tr><td>Subsistema de log</td><td>`com.lab3dvlp.CtrlStationAgent`</td></tr><tr><td>Time (team) do Developer ID</td><td>`S9DE935KXJ` (LAB3 Desenvolvimento de Software Ltda ME)</td></tr><tr><td>Intervalo do heartbeat</td><td>30 segundos</td></tr><tr><td>Início/reinício automático</td><td>LaunchAgent `RunAtLoad` + `KeepAlive`</td></tr></tbody></table>