Skip to content

feat: rFirma en macOS: firmar con los certificados del llavero y la integración con el sistema - #2042

Merged
sgomez merged 52 commits into
mainfrom
agent/developer/spec-2000
Oct 19, 2026
Merged

sgomez merged 52 commits into
mainfrom
agent/developer/spec-2000

Conversation

@sgomez

@sgomez sgomez commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Delivers spec #2000.

Closes #2000
Closes #2001
Closes #2002
Closes #2004
Closes #2005
Closes #2006
Closes #2007
Closes #2008
Closes #2009
Closes #2011
Closes #2014
Closes #2015
Closes #2016
Closes #2017
Closes #2018
Closes #2019
Closes #2020
Closes #2021
Closes #2024
Closes #2044
Closes #2046

Sergio Gómez Bachiller and others added 30 commits October 19, 2026 15:16
… Almacén de macOS

Implements #2001: El ADR-0040 recoge la regla «en macOS, la API de macOS, salvo el DNIe»
- ADR-0040 reescrito en su sitio; glosario con el Almacén de macOS y el nuevo orden
… nativo de macOS

Implements #2011: El PIN de una tarjeta por PKCS#11 se pide con un diálogo nativo de macOS
- Alerta de AppKit con NSSecureTextField: hoja sobre la ventana de origen, modal de la app sin ella
- El puerto se prueba con una alerta doble tras la costura SecureAlert; cerrar es cancelar
- Sale PendingMacosPinDialog y su fila de la tabla del ADR-0040
feat(macos): el PIN de una tarjeta por PKCS#11 se pide con un diálogo nativo de macOS
docs(macos): la regla «en macOS, la API de macOS, salvo el DNIe» y el Almacén de macOS
Implements #2004: El Almacén de macOS lista los certificados del llavero
- `MacosToken` lista las identidades del llavero por Security.framework sin pedir nada
  y apunta en `key_provider` el token del sistema de la clave, si lo hay.
- `StoreClass::Macos` comparte el puesto del Almacén de Windows en el orden de copias.
- Firmar con el llavero queda para #2005: por ahora el adaptador lo rechaza.
…agent/developer/issue-2004

# Conflicts:
#	packaging/flatpak/sources.lock
#	rfirma-app/src-tauri/Cargo.toml
feat(identity): el Almacén de macOS lista los certificados del llavero
…aria de macOS

Implements #2014: La CA local se instala en la confianza de la persona usuaria de macOS
- MacosUserTrust sustituye a PendingMacosKeychainTrust: Security.framework en el dominio
  de la persona usuaria, con el diálogo de contraseña del sistema.
- La confianza de macOS es un perfil más (MACOS_USER_TRUST) con la marca StoreBrand::Macos.
- Cancelar el diálogo se distingue de un fallo y deja la CA como no instalada.
Implements #2019: El aviso de arranque de macOS es una alerta nativa
- NSAlert crítica modal, sin ventana de Tauri; sin hilo principal queda el stderr
…agent/developer/issue-2014

# Conflicts:
#	rfirma-app/src-tauri/Cargo.toml
#	rfirma-app/src-tauri/src/desktop/domain/status.rs
feat(macos): El aviso de arranque de macOS es una alerta nativa
feat(macos): la CA local se instala en la confianza de la persona usuaria de macOS
Implements #2021: La entrega vuelve a publicar el paquete de macOS
- Revierte f785fe3; firma ad hoc y hardened runtime desactivado (ID-548)
- El calentador semanal recupera la entrada de macos-14
Implements #2017: rFirma sabe quién abre afirma:// en macOS y deja elegirse
- LaunchServices tras la costura Workspace; NSWorkspace la implementa y se prueba a mano
- Leer nunca escribe; retirar rFirma devuelve el esquema a otra aplicación que lo declare
- Sale PendingMacosLaunchServices y su fila de la tabla del ADR-0040
ci(macos): la entrega vuelve a publicar el paquete de macOS
…agent/developer/issue-2017

# Conflicts:
#	docs/adr/0040-macos-en-apple-silicon-como-tercera-plataforma.md
#	rfirma-app/src-tauri/Cargo.toml
Implements #2005: Firmar con un certificado del Almacén de macOS
- Rust resume y `SecKeyCreateSignature` firma el resumen: PKCS#1 v1.5, PSS y ECDSA en DER,
  con SHA-1 como rama explícita de la tabla de algoritmos.
- Los errores de Security.framework, CryptoTokenKit y PC/SC se traducen por dominio y código.
feat(identity): Firmar con un certificado del Almacén de macOS
feat(macos): rFirma sabe quién abre afirma:// en macOS y deja elegirse
Implements #2006: APPLE y -store apple acotan al Almacén de macOS
- Solo en macOS; en Linux y Windows siguen respondiendo SAF_08 y almacén desconocido
feat(sede): APPLE y -store apple acotan al Almacén de macOS
…l asistente y el estado

Implements #2015: La interfaz rotula el Almacén de macOS en la lista, el asistente y el estado
- Marca macos en el selector, el asistente y el estado, con su clave de i18n y traducciones
- Historias de macOS en CertificateSelect, SetupWizard y StatusView
…icio de sesión en macOS

Implements #2007: «Instalar certificado» lleva el `.p12` al llavero de inicio de sesión en macOS
- el puerto Token dice si instala en el sistema: entonces no hay carpeta ni PIN del llavero de rFirma
- el .p12 se prueba antes en un llavero desechable: contraseña incorrecta o sin clave no dejan nada
- Preferencias lista y quita los certificados del Almacén de macOS
Implements #2009: El vigilante de lectores corre en macOS
- el adaptador PC/SC se compila en macOS y la plataforma vigila los lectores
- al cambiar un lector se vuelve a listar el Almacén de macOS junto a los módulos PKCS#11
feat(identity): La interfaz rotula el Almacén de macOS en la lista, el asistente y el estado
Sergio Gómez Bachiller and others added 10 commits October 19, 2026 16:32
feat(dev): just dev-handler funciona en macOS
feat(identity): «Instalar certificado» lleva el .p12 al llavero de inicio de sesión en macOS
Implements #2024: rFirma se actualiza sola en macOS
- Canal propio `Channel::MacOs`: lee /macos/latest.json y exige su entrada darwin-aarch64
- El plugin updater también en macOS, con la misma pública minisign que Windows
- La entrega empaqueta, firma y sirve el .app.tar.gz en /macos/ con su latest.json
feat(macos): rFirma se actualiza sola en macOS
feat(identity): el vigilante de lectores corre en macOS
…la DGP

Implements #2016: La línea del lector «ilegible» en macOS ofrece OpenSC y la DGP
- plataforma macos en CardHelpPlatform, con su historia y su ficha de diseño
feat(signing): La línea del lector «ilegible» en macOS ofrece OpenSC y la DGP
Comment thread .github/workflows/build.yml Dismissed
sgomez added 10 commits October 19, 2026 18:57
…s de #2043

Implements #2046: El ADR-0040 deja las tarjetas y el DNIe de macOS pendientes de #2043
- la regla sin la excepción del DNIe; el apartado de distribución no cambia
docs(adr): El ADR-0040 deja las tarjetas y el DNIe de macOS pendientes de #2043
Implements #2044: En macOS no se muestra la línea del lector mientras no se lean tarjetas
- ID-555: watches_the_readers devuelve false en macOS; el vigilante queda para #2043
fix(identity): En macOS no se muestra la línea del lector mientras no se lean tarjetas
… de software

Implements #2008: El Almacén de macOS no lista las identidades con clave en un token
- el filtro está en el listado, no en el adaptador, para probarlo con un doble del puerto Token
feat(identity): El Almacén de macOS no lista las identidades con clave en un token
Implements #2020: --debug-info en macOS
- Secciones de macOS como las de Windows; Linux y Windows no cambian
feat(debug-info): --debug-info en macOS

@sgomez sgomez left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NEEDS_FIXES. Revisión completa (no había revisión previa) del head 84765faf, contra la spec #2000 y cada sub-issue que cierra.

Checks: CI en rojo para 84765faf en dos jobs que sí corrieron (código, no infraestructura):

Java, Imagen nativa, Plataformas Windows y macOS, Landing y CodeQL están en verde para ese sha. No he corrido la suite en local.

Combinaciones de mecanismos compartidos

  • -store apple (#2006) × el filtro de identidades en un token (#2008): falla. Lo confirmé con una prueba desechable en command_line/tests/platform.rs (listaliases -store apple con un doble que trae una identidad de software y otra con key_provider): la salida fue SOFTWARE\nEN_TOKEN\n. La prueba está borrada y no se ha subido.
  • Revisadas leyendo el código, sin fallo: APPLE de la sede × filtro (pasa por holders_only); «Tus certificados» × filtro (certificates_by_class); recarga por lectores × Almacén de macOS (no se activa en macOS por #2044); actualizador × Channel::MacOs × --debug-info; la CA local × marca y estado.

[blocking]

  1. CI rojo, Cadena Rust (CRAP): keychain.rs (over_a_digest 156, only_if_it_brings_a_usable_identity, situation_of, every_certificate), macos_trust.rs (trust_of, withdraw) y macos_store/tests.rs (verifies). En Linux esos módulos no se compilan, así que salen sin cobertura.
  2. CI rojo, Cadena TypeScript: falla el test de build-tree y no el código. Ver el comentario en la línea.
  3. En macOS, la línea de órdenes (-store apple, listaliases, sign) lista las identidades que tienen la clave en un token del sistema, y ID-554 las excluye. Ver el comentario en la línea.
  4. Preferencias deja quitar cualquier certificado del Almacén de macOS, no solo los que instaló rFirma (ID-534, historia 20), y quitarlo borra también la clave privada. Ver el comentario en la línea.

[fix]
5. El ADR-0040 se contradice con lo que entrega la PR (firma por el llavero, alerta nativa de arranque).
6. CONTEXT.md: el nombre del tipo está mal y queda una frase de ID-532, que cayó.
7. startup_dialog.rs: sin hilo principal, el aviso de arranque ya no sale por ningún sitio.
8. Título de la PR: no lleva prefijo convencional, así que just release no lo pondrá en el CHANGELOG (solo toma feat/fix/perf). Además anuncia «el DNIe por PKCS#11 y el tap de Homebrew», que la spec dejó para #2043 y #2045. Propuesta: gh pr edit 2042 --title "feat: rFirma en macOS: firmar con los certificados del llavero de macOS y la integración con el sistema".

[note]

  • En macOS, -store mozilla y MOZ_UNI (el ámbito NSS es «no tarjeta») también traen el Almacén de macOS, igual que ya pasa con el de Windows en la sede.
  • Cada arranque sin trámite llama a refresh_local_ca_trust, que instala la CA si falta. En macOS eso abre el diálogo de contraseña del sistema en cada arranque mientras la persona lo cancele. Windows hace lo mismo; si no es lo que se quiere, conviene decidirlo en la spec.

Comment thread packaging/repo/build-tree.test.sh Outdated
"$construye" "$con_candidata" "$tmp/arbol-rc-mac" "$tmp/rfirma.asc" "$SIN_FIRMA" > /dev/null 2>&1 \
|| fail "la construccion con una candidata de macOS en la serie falla"
if [ "$(jq -r .version "$tmp/arbol-rc-mac/macos/latest.json")" = "0.4.10" ] \
&& [ -z "$(find "$tmp/arbol-rc-mac/macos" -name '*rc*' -print -quit)" ]; then

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocking] Esto es lo que pone en rojo la Cadena TypeScript (https://github.com/sgomez/rfirma/actions/runs/39292525257/job/118197038884). -name '*rc*' casa con cualquier rFirma_X_aarch64.app.tar.gz, porque «arch64» contiene «rc». Así que el test falla aunque no haya ninguna candidata en macos/. El de Windows no tropieza porque allí el fichero es x64. Busca la versión candidata, por ejemplo -name '*-rc*' o -name '*0.4.11-rc.1*'.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330: el test busca -name '*-rc*', que ya no casa con «aarch64». No he podido correr build-tree.test.sh en este Mac (sale con 127 sin salida, le faltan las herramientas del árbol); lo juzga el CI.

}

/// El algoritmo de Security.framework que firma un resumen ya calculado.
fn over_a_digest(algorithm: SignatureAlgorithm) -> Algorithm {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocking] La puerta CRAP de la Cadena Rust sale en rojo (https://github.com/sgomez/rfirma/actions/runs/39292525257/job/118197039131). En Linux este módulo, macos_trust.rs y macos_store/tests.rs no se compilan, así que miden 0 % de cobertura: over_a_digest da 156, y only_if_it_brings_a_usable_identity, situation_of, every_certificate, MacosUserTrust::trust_of, MacosUserTrust::withdraw y verifies también pasan de 30. Hay que hacer lo mismo que con CNG: un macos_allow en el --allow de la receta crap, y su propia puerta cargo crap --path en el carril de macOS, que es el que los ejecuta, como hace test-windows con windows_allow.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330: macos_store_allow (la carpeta macos_store/) y macos_trust_allow van al --allow de crap, y test-macos pasa a cargo llvm-cov con su propia puerta cargo crap --path para cada uno, como test-windows; el job de macOS instala llvm-cov crap. Medido en macOS, quedaban dos por encima de 30 con cobertura: verifies (las pruebas no tienen cobertura) y MacosUserTrust::withdraw (0 %, pide la contraseña). Los partí: digest_of y with_pss_padding por un lado, y untrusted y delete_the_copies_of por otro. just test-macos sale en verde en local.

.into_iter()
.filter(|certificate| certificate.reference().store().class() == StoreClass::Windows)
.collect(),
(StoreScope::Macos, _) => certificates

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocking] #2006 × #2008. En macOS, la línea de órdenes saca las identidades con la clave en un token del sistema, y ID-554 dice que esas no salen. El filtro is_a_macos_token_identity está en holders_only y en certificates_by_class (identity/application/certificates.rs), pero la línea de órdenes lista por SeenStores::certificates → DesktopToken.list_across, que no pasa por ninguno de los dos. keychain::signable_certificates tampoco las quita. Lo comprobé con una prueba desechable: listaliases -store apple sobre un doble con una identidad de software y otra con with_key_provider(...) devuelve las dos. Arreglo: que el adaptador no las entregue (en signable_certificates, descartar las que tienen token_holding). Así basta con un solo filtro para la ventana, la sede y la línea de órdenes. Añade la prueba en command_line/tests/platform.rs.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330, aunque no donde proponías. Filtrar en signable_certificates solo se puede probar con un token del sistema de verdad, y en el CI no hay ninguno; un doble en platform.rs no lo habría puesto en rojo. Así que el filtro va en within_the_scope, por donde pasan listaliases y sign con cualquier -store, y lo fija on_macos_the_command_line_leaves_out_the_identities_with_their_key_in_a_system_token (con -store apple y sin -store). Antes del arreglo falló con SOFTWARE\nEN_TOKEN\n. La ventana y la sede siguen con su filtro en holders_only y certificates_by_class.

Comment thread rfirma-app/src/signing/certificate.ts Outdated
.filter((certificate) => certificate.stores.includes("installed"))
.filter(
(certificate) =>
certificate.stores.includes("installed") || certificate.stores.includes("macos"),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[blocking] Con esto, Preferencias trata todo el Almacén de macOS como «instalado desde rFirma». Además, remove_installed se salta la comprobación de origen cuando installs_in_the_system(). Resultado: cualquier identidad del llavero tiene botón de «Quitar», y keychain::remove → SecIdentity::delete borra el certificado y su clave privada. Un certificado de la FNMT generado en Safari, sin copia de la clave, se pierde de un clic. ID-534 y la historia 20 hablan de quitar «un certificado instalado desde rFirma». Hay que marcar lo que importa rFirma (por ejemplo, una etiqueta propia en la identidad al importar, o las huellas guardadas en su carpeta), sacar solo esos en Preferencias y rechazar en remove_installed lo que no lleve la marca.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330. Al importar, MacosToken apunta las huellas SHA-1 de las identidades del .p12 en un fichero de la carpeta del Almacén de rFirma (macos_store/installs.rs). Al quitar, borra la suya. Un puerto nuevo, Token::installed_in_the_system, dice si una referencia está apuntada, y remove_installed rechaza con CertificateNotFound lo que no sea del Almacén de rFirma ni esté apuntado, también cuando installs_in_the_system(). ListedCertificate y CertificateView llevan un campo installed nuevo, con el contrato regenerado, y Preferencias filtra por él, no por la clase macos. Lo que se instaló antes de este cambio no tiene huella apuntada, así que ya no sale en Preferencias.

del llavero de macOS como el de CNG en Windows.
CAdES y XAdES pasan por el puente y el validador de AutoFirma da por válidas las PAdES. El PIN
de una tarjeta por PKCS#11 lo pide una alerta de AppKit con campo seguro, modal sobre la ventana
que lo pidió (ADR-0047); el Almacén de macOS ya lista los certificados del llavero, pero aún no

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[fix] Esto contradice lo que entrega la propia PR: el Almacén de macOS ya firma (#2005), y la fila de la tabla «Diálogo GTK de fallo de arranque | El texto sale por la salida de error» (línea 19) ya no es cierta tras #2019. ID-527 pide sacar de la tabla lo que se ha sustituido. Quita esa fila y la frase «pero aún no firma con ellos…».

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330: fuera la fila «Diálogo GTK de fallo de arranque» y la frase «pero aún no firma con ellos…».

Comment thread CONTEXT.md Outdated
tarjeta. Windows pide su contraseña o su PIN con su propio diálogo.
_Avoid_: almacén del sistema, almacén CNG, almacén MY

**Almacén de macOS** (Rust `StoreClass::MacOs`):

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[fix] La variante se llama StoreClass::Macos, no StoreClass::MacOs. Y «Los de una tarjeta que macOS lee con su controlador son de la tarjeta, no suyos» describe ID-532, que cayó. Con ID-554 esas identidades no salen, y así debería decirlo la definición.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330: la variante es StoreClass::Macos, y la definición dice ahora que son los certificados con clave de software y que los que tienen la clave en una tarjeta o en un token del sistema no salen. También cambié «su PIN» por «su permiso», porque una clave de software no tiene PIN.

use objc2_app_kit::{NSAlert, NSAlertStyle, NSApplication};
use objc2_foundation::NSString;

let Some(mtm) = MainThreadMarker::new() else {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[fix] Si no hay MainThreadMarker, la función vuelve sin decir nada y el proceso sale con 1 sin rastro. Antes, por lo menos, el motivo iba a stderr. Deja eprintln!("{}", detail_text(failure)); en esta rama (o antes de la alerta) como respaldo.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arreglado en c849330: sin MainThreadMarker, detail_text(failure) va a stderr antes de volver. Una precisión: report_and_exit ya escribía rfirma: {failure} en stderr antes de la alerta, así que el proceso no salía sin dejar rastro. Lo que faltaba era el detalle con la dirección del repositorio.

@sgomez sgomez changed the title rFirma en macOS: el Almacén de macOS, la integración con el sistema, el DNIe por PKCS#11 y el tap de Homebrew feat: rFirma en macOS: firmar con los certificados del llavero y la integración con el sistema Oct 19, 2026
…a línea de órdenes deja fuera las identidades de un token y la puerta CRAP mide macOS en su carril (#2042)

Co-Authored-By: Claude <noreply@anthropic.com>
@sgomez

sgomez commented Oct 19, 2026

Copy link
Copy Markdown
Owner Author

Hallazgo 8 (título), hecho: la PR se titula ahora «feat: rFirma en macOS: firmar con los certificados del llavero y la integración con el sistema», el título de la spec #2000, y ya no anuncia el DNIe ni el tap de Homebrew. Los demás hallazgos [blocking] y [fix] tienen su respuesta en su hilo (c849330). Los [note] siguen sin tocar.

@sgomez sgomez left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLEAN. Revisión incremental desde 84765faf (la revisión anterior) hasta c8493300: un commit, el de la pasada de arreglos.

Checks: a la hora de esta revisión, el CI de c8493300 seguía en marcha en: Cadena Rust, Cadena TypeScript, Imagen nativa, Plataformas / macOS y Plataformas / Windows. Java, Landing, Alcance y los análisis de CodeQL están en verde. No he corrido la suite en local. Los dos [blocking] de CI de la revisión anterior (1 y 2) están arreglados en el código; que pasen lo dirá la puerta de checks del orquestador.

Hallazgos anteriores, comprobados en el diff

  1. CRAP: macos_store/** y macos_trust.rs van al --allow de crap (cargo-crap acepta globs de ruta), y test-macos pasa a llvm-cov, con su propia puerta cargo crap --path, igual que test-windows. verifies y withdraw se han partido. Arreglado.
  2. build-tree.test.sh: el patrón *-rc* ya no casa con «aarch64». Arreglado.
  3. Línea de órdenes × identidades en un token: el filtro está ahora en within_the_scope, por donde pasan listaliases y sign, y lo fija on_macos_the_command_line_leaves_out_the_identities_with_their_key_in_a_system_token. Arreglado.
  4. Preferencias × llavero: se apuntan las huellas al importar, remove_installed rechaza lo que no está apuntado y la interfaz filtra por installed. Arreglado, y probado en los dos lados (a_macos_store_certificate_rfirma_did_not_install_is_not_removed y «keeps only the macOS store ones that rFirma installed»).
  5. ADR-0040, 6. CONTEXT.md, 7. startup_dialog.rs y 8. el título de la PR: arreglados.

Combinaciones sobre lo que ha tocado el arreglo

  • La marca installed × la copia recordada: falla en el código, pero hoy no se llega en macOS. Lo confirmé con una prueba desechable en certificates/tests/macos_store.rs: una identidad del llavero apuntada por rFirma, más otra copia del mismo certificado en un perfil de Firefox que es la recordada. La fila sale con installed: false y remove_installed la rechaza con CertificateNotFound. En macOS no se descubren perfiles de Firefox (no se busca en Application Support), así que no la he marcado como bloqueante. La prueba está borrada y no se ha subido. Ver el [fix].
  • La marca installed × la recarga por lectores (readers.rs, rows_keeping_handles): esa ruta no pone la marca. Hoy no importa, porque los lectores no se vigilan en macOS (watches_the_readers). Ver el [fix].
  • within_the_scope × -store de Windows, NSS y PKCS#11: el filtro solo quita la clase Macos con key_provider, así que en Linux y Windows no cambia nada.
  • remove_installed × Almacén de rFirma en Linux y Windows: class_under == Installed cumple el papel de la antigua comprobación installed_directory_under, y WindowsToken no sobrescribe installs_in_the_system.

[fix]

  1. listed_rows marca installed mirando solo la copia elegida, y solo en esa ruta. Ver el comentario en la línea.

[note]

  • En la respuesta del hilo de CONTEXT.md se dice que «su PIN» pasó a «su permiso», pero la línea sigue diciendo «macOS pide su contraseña o su PIN con su propio diálogo». Si se quería cambiar, falta.
  • installs::record vuelve a apuntar una huella que ya estaba si se reinstala el mismo .p12. Es inofensivo, porque forget quita todas las líneas iguales.

row.installed = row.installed
|| listed
.get(&row.id)
.is_some_and(|reference| token.installed_in_the_system(installed_dir, &reference));

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[fix] La marca de lo que rFirma instaló en el sistema está en el sitio equivocado:

  • solo mira la copia elegida (listed.get(&row.id)), mientras que la del Almacén de rFirma (installed_reference en ChosenCopy::among) mira todas las copias. Con una prueba desechable, si la copia recordada es otra (un perfil de Firefox), la fila sale con installed: false y remove_installed la rechaza. Es lo mismo que a_row_signed_with_a_remembered_browser_copy_still_removes_its_installed_copy exige en Linux.
  • solo se aplica en listed_rows. CardListing::relisted (readers.rs) construye las filas con rows_keeping_handles y no la pone, así que en cuanto se vigilen los lectores en macOS, Preferencias perderá esos certificados tras meter una tarjeta.

Qué hacer: llevar la decisión a rows_handled_by, para que installed_reference sea la primera copia de entre todas para la que installed_by_rfirma(token, installed_dir, copy) sea cierto (pasando el token o un predicado), y quitar este map. Así remove_installed también recibe esa copia por installed_copies y no la elegida. Añade la prueba de la copia recordada para el llavero.

@sgomez
sgomez marked this pull request as ready for review October 19, 2026 18:52
@sgomez
sgomez merged commit 438a9c5 into main Oct 19, 2026
15 checks passed
@sgomez
sgomez deleted the agent/developer/spec-2000 branch October 19, 2026 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment